mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
1416 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
687a1b7de4 | ||
|
|
7a557013ae | ||
|
|
80e377b668 | ||
|
|
d22506c645 | ||
|
|
41f82fb45f | ||
|
|
5e839d50b4 | ||
|
|
b15f323f03 | ||
|
|
667b7d8508 | ||
|
|
a868575436 | ||
|
|
042ffed6c4 | ||
|
|
e80930247f | ||
|
|
2c97242739 | ||
|
|
e3fab47508 | ||
|
|
472190bedc | ||
|
|
5cf8c05a22 | ||
|
|
23621857bb | ||
|
|
726c709f97 | ||
|
|
1205f9107e | ||
|
|
e34c3e7c3b | ||
|
|
38892bbf6a | ||
|
|
ca2b73f64a | ||
|
|
443fdd6d69 | ||
|
|
29261a0eae | ||
|
|
d29cf2d0e2 | ||
|
|
dad99376a5 | ||
|
|
171f4a21e8 | ||
|
|
57cc8237f7 | ||
|
|
36fc1d9d72 | ||
|
|
4075159933 | ||
|
|
da7d6c8446 | ||
|
|
1bb0bdec24 | ||
|
|
e6d17e6273 | ||
|
|
013289480d | ||
|
|
ed935dfef1 | ||
|
|
232d252885 | ||
|
|
cf3b54fdcb | ||
|
|
be6474af63 | ||
|
|
39e4e3f205 | ||
|
|
d7caba8b65 | ||
|
|
c80d563afb | ||
|
|
13b941d8ee | ||
|
|
05e89ffceb | ||
|
|
9a2704056a | ||
|
|
d0f0076c59 | ||
|
|
fb91efd47e | ||
|
|
e74868f4c6 | ||
|
|
1f9f34b9a7 | ||
|
|
3b69a8d27a | ||
|
|
56a6928635 | ||
|
|
6ee1717238 | ||
|
|
23e9ed81a2 | ||
|
|
1465355c54 | ||
|
|
20e3ab70b2 | ||
|
|
00dc93b65b | ||
|
|
e2fe9dd9ab | ||
|
|
63d384d0cd | ||
|
|
7584d867e1 | ||
|
|
1068022dfb | ||
|
|
5859e80364 | ||
|
|
6886a47305 | ||
|
|
208ef29706 | ||
|
|
de04c97696 | ||
|
|
84c1aa9990 | ||
|
|
1c89c45ae9 | ||
|
|
2fb5d62927 | ||
|
|
6692d95ee2 | ||
|
|
c93c014bc6 | ||
|
|
9ce0ac38e5 | ||
|
|
733b289209 | ||
|
|
73570cbe38 | ||
|
|
79f0c66b4d | ||
|
|
8af083c847 | ||
|
|
37ac424e9a | ||
|
|
8e08ff559f | ||
|
|
941cc937d3 | ||
|
|
3670fe2385 | ||
|
|
6baedfe946 | ||
|
|
c163c06a65 | ||
|
|
9e7c0fd2b0 | ||
|
|
21d0cc8cdf | ||
|
|
b961e47bfe | ||
|
|
817337af30 | ||
|
|
d96f25619a | ||
|
|
bb94abd88a | ||
|
|
3612aca5fe | ||
|
|
c3cb03c640 | ||
|
|
ed0736d73d | ||
|
|
2e9950afe8 | ||
|
|
fe387888bd | ||
|
|
455c3c19ca | ||
|
|
f862e80be9 | ||
|
|
3ee25170c3 | ||
|
|
587f0bd086 | ||
|
|
6b1543a6a8 | ||
|
|
90a6f4ba98 | ||
|
|
e333b8bc1e | ||
|
|
58e583e39b | ||
|
|
7cddb39969 | ||
|
|
96c97d4103 | ||
|
|
b0a16fb619 | ||
|
|
fac9947ebe | ||
|
|
ebe174c868 | ||
|
|
be02aaec72 | ||
|
|
3f3014f626 | ||
|
|
9a728b15a2 | ||
|
|
5da463e1f7 | ||
|
|
dcfc7a8896 | ||
|
|
a86c774932 | ||
|
|
8b82004359 | ||
|
|
a690e7b267 | ||
|
|
d0f013477b | ||
|
|
54935e2e70 | ||
|
|
0c64849aab | ||
|
|
a157985e01 | ||
|
|
4196757de7 | ||
|
|
0dffbd66bb | ||
|
|
36869b3aed | ||
|
|
bb8b9da391 | ||
|
|
e2d02d5943 | ||
|
|
fde53bffd7 | ||
|
|
2a470c4217 | ||
|
|
6e70d8afb4 | ||
|
|
fb547ef76b | ||
|
|
af4c0851c1 | ||
|
|
3e25d5f247 | ||
|
|
831a8c8db4 | ||
|
|
230af70be4 | ||
|
|
42a8ab34f1 | ||
|
|
369d8c57ae | ||
|
|
12e247acc6 | ||
|
|
3197ec8e72 | ||
|
|
abb7010820 | ||
|
|
1b97fcd448 | ||
|
|
d20e4e0df4 | ||
|
|
152fcc8ec4 | ||
|
|
61c9c429d4 | ||
|
|
d2593e1d62 | ||
|
|
d98b0d9f79 | ||
|
|
9840a6912d | ||
|
|
7c065bfadf | ||
|
|
b2fd562983 | ||
|
|
5eaec84785 | ||
|
|
439569cfa3 | ||
|
|
b23dce03a1 | ||
|
|
291aa2eb30 | ||
|
|
b988f75a35 | ||
|
|
8095fbf982 | ||
|
|
5d6053173a | ||
|
|
a4ccd7b865 | ||
|
|
83661492e7 | ||
|
|
a4559ab17e | ||
|
|
5def38ad69 | ||
|
|
cf7e83ecc5 | ||
|
|
034af8354d | ||
|
|
f6f5c9e9e6 | ||
|
|
99ebcaec3a | ||
|
|
4d2f1396cb | ||
|
|
51c203bab0 | ||
|
|
335de0c49a | ||
|
|
cd70bba332 | ||
|
|
d0478a5637 | ||
|
|
694fc87b1d | ||
|
|
fc814b87dc | ||
|
|
4835199125 | ||
|
|
d02af5cc4c | ||
|
|
e6d2490b9c | ||
|
|
8d1c4a23de | ||
|
|
033f2bbbf2 | ||
|
|
6a055990f9 | ||
|
|
160933f9de | ||
|
|
325dd44e81 | ||
|
|
5a4afbef84 | ||
|
|
4399895d2e | ||
|
|
62a10df765 | ||
|
|
e4e87f1cb2 | ||
|
|
5dc28cc9a7 | ||
|
|
29fdc7a5be | ||
|
|
3e9ebd24f2 | ||
|
|
e810c760fd | ||
|
|
207874aa2d | ||
|
|
843693d676 | ||
|
|
cc9230824a | ||
|
|
ac02aecb04 | ||
|
|
b579ca44eb | ||
|
|
befdce51b4 | ||
|
|
dc2b21e9b2 | ||
|
|
6a94ca3187 | ||
|
|
71b69a627f | ||
|
|
ffb36db5a6 | ||
|
|
e69899fb49 | ||
|
|
c75b247a90 | ||
|
|
52c6956d1a | ||
|
|
b919ab790b | ||
|
|
44ee8aecfd | ||
|
|
f3d7c452d2 | ||
|
|
aae774a279 | ||
|
|
227c54c786 | ||
|
|
3afb42496b | ||
|
|
f50575d147 | ||
|
|
b6d5f18c93 | ||
|
|
20e55fc5d4 | ||
|
|
a6f8bae69f | ||
|
|
d41988d8b2 | ||
|
|
cc718435b3 | ||
|
|
05421cf84b | ||
|
|
2958adc47f | ||
|
|
12e3c11eb6 | ||
|
|
23d581d377 | ||
|
|
5a51a25fd0 | ||
|
|
31cfed0aa8 | ||
|
|
76dfa611ed | ||
|
|
f40625f5c4 | ||
|
|
de5d18188f | ||
|
|
76ef752957 | ||
|
|
3365b42bbe | ||
|
|
74af96dbf6 | ||
|
|
491291ae24 | ||
|
|
cabc5c80d3 | ||
|
|
dc956c485a | ||
|
|
a1e97ad4a4 | ||
|
|
78cc4de9a1 | ||
|
|
783087fd57 | ||
|
|
9fdb131686 | ||
|
|
4ed1ac0078 | ||
|
|
6d0451ccce | ||
|
|
7874c0efcb | ||
|
|
cdb4d83ead | ||
|
|
d15788d00a | ||
|
|
c58ec376b6 | ||
|
|
9e66d988e7 | ||
|
|
8755792077 | ||
|
|
bf2f6397c8 | ||
|
|
907e1b80b2 | ||
|
|
e8c50640d7 | ||
|
|
ee1192679e | ||
|
|
976fb18a8f | ||
|
|
baa304f370 | ||
|
|
d310b01db1 | ||
|
|
e855f6c073 | ||
|
|
5920edf6e4 | ||
|
|
10f205bb52 | ||
|
|
3a34a8880c | ||
|
|
7a311f93f7 | ||
|
|
192e11e7b7 | ||
|
|
2ce9f1c77f | ||
|
|
5bf45d9285 | ||
|
|
ca6b4bf0f9 | ||
|
|
a4f30c3682 | ||
|
|
b76d2eac7f | ||
|
|
5f64d7a353 | ||
|
|
5f478e5aa1 | ||
|
|
5aac789e0e | ||
|
|
e53fc91282 | ||
|
|
fb5ece805f | ||
|
|
a431207e52 | ||
|
|
28e375c4f6 | ||
|
|
02e97422ed | ||
|
|
13d26dc53d | ||
|
|
2a182f55ae | ||
|
|
1b423139e6 | ||
|
|
4f91dd40ed | ||
|
|
b59fba5845 | ||
|
|
09bda74e7d | ||
|
|
8ba062d952 | ||
|
|
f49f2f38f0 | ||
|
|
b2aa70c6ef | ||
|
|
8a0509b3b2 | ||
|
|
d508384d39 | ||
|
|
4b7655fd10 | ||
|
|
a66d059acc | ||
|
|
ca228e46b5 | ||
|
|
1e45bb79ab | ||
|
|
261a6ca017 | ||
|
|
c27fb4116e | ||
|
|
9d4b77a65a | ||
|
|
b3da0ab888 | ||
|
|
26890b6525 | ||
|
|
49b0440c47 | ||
|
|
f0953db3ba | ||
|
|
da5d88f04e | ||
|
|
ac271e76b1 | ||
|
|
7dcf6ff50b | ||
|
|
27c2c1e75c | ||
|
|
37b199d34a | ||
|
|
4d2c948281 | ||
|
|
cf8fe16a48 | ||
|
|
7080d02af4 | ||
|
|
63d93ad1ab | ||
|
|
de64e8ec22 | ||
|
|
0519afba1d | ||
|
|
95e4ab99e7 | ||
|
|
afb7dbf81a | ||
|
|
1a75b17cd0 | ||
|
|
5e47c18e3f | ||
|
|
3e056afb1c | ||
|
|
dd18c0ddd5 | ||
|
|
a9bc8220fd | ||
|
|
1c35fb3c89 | ||
|
|
2fc84325c7 | ||
|
|
d2f130c3fc | ||
|
|
d97a397139 | ||
|
|
15919b7c98 | ||
|
|
2ce07042fd | ||
|
|
9b5357da5a | ||
|
|
71695ab791 | ||
|
|
3270676e77 | ||
|
|
121553d1a6 | ||
|
|
1546d210c5 | ||
|
|
85fe5e1940 | ||
|
|
d4714ed14e | ||
|
|
d5798b43de | ||
|
|
9fb0755572 | ||
|
|
45a345e93d | ||
|
|
3dcf735482 | ||
|
|
29b7104a53 | ||
|
|
752352a683 | ||
|
|
eebe0035b5 | ||
|
|
1793a0b5ce | ||
|
|
5aa486cf11 | ||
|
|
a097526956 | ||
|
|
5820093e58 | ||
|
|
4b09a89758 | ||
|
|
7b055388b7 | ||
|
|
518b794491 | ||
|
|
085b339b8b | ||
|
|
7704cdc90e | ||
|
|
5f19af9e01 | ||
|
|
edfcbab86f | ||
|
|
aaa13c0011 | ||
|
|
71de5ea909 | ||
|
|
dd216755ff | ||
|
|
91d842e1ec | ||
|
|
3147f7f6c2 | ||
|
|
c7b83d2c44 | ||
|
|
5b7e44f0aa | ||
|
|
61e5435081 | ||
|
|
5e78baa061 | ||
|
|
90e326504b | ||
|
|
3ae21ea48e | ||
|
|
2cbe46daff | ||
|
|
ee1b0d8c67 | ||
|
|
7500a5ea0b | ||
|
|
a88a635847 | ||
|
|
249dd70273 | ||
|
|
9e989676d8 | ||
|
|
862c0ef83d | ||
|
|
d786974a45 | ||
|
|
d1bc6cf098 | ||
|
|
853bdbf494 | ||
|
|
bbd245b47b | ||
|
|
6a83a5e468 | ||
|
|
7904446c47 | ||
|
|
c5db5875f7 | ||
|
|
5506e8491d | ||
|
|
a066e4e5c5 | ||
|
|
6e42513acd | ||
|
|
d944e09eb9 | ||
|
|
b0625d2aa3 | ||
|
|
3dfb4891c7 | ||
|
|
4f946cb44e | ||
|
|
94e444c90f | ||
|
|
aa92669d92 | ||
|
|
5324c9ebba | ||
|
|
74d51a7700 | ||
|
|
0f88ee7d0c | ||
|
|
016492375f | ||
|
|
1ce30b9e10 | ||
|
|
ab0fea9199 | ||
|
|
ed5bbfe36d | ||
|
|
7918c30b90 | ||
|
|
f54556518e | ||
|
|
e328d015f1 | ||
|
|
af31f19ebb | ||
|
|
5009ea56c0 | ||
|
|
9620893d72 | ||
|
|
269bf8e334 | ||
|
|
74549c327e | ||
|
|
835926e174 | ||
|
|
bc8ec5b6b4 | ||
|
|
dfeb0e8432 | ||
|
|
614557994e | ||
|
|
3249f16d85 | ||
|
|
d8793dcf56 | ||
|
|
c55f5b34ee | ||
|
|
d4263b1012 | ||
|
|
0d263f155b | ||
|
|
25f6e0c681 | ||
|
|
393706498e | ||
|
|
c4f9c3b53e | ||
|
|
f0a70c7aae | ||
|
|
d828b0b96e | ||
|
|
2f692dcc3a | ||
|
|
e1600f209f | ||
|
|
8a4138da55 | ||
|
|
f4371bfef8 | ||
|
|
a79579da6f | ||
|
|
2b271e7b17 | ||
|
|
384a018906 | ||
|
|
ad79b125e7 | ||
|
|
b7bb56bdca | ||
|
|
3a2e1ce538 | ||
|
|
20131c32af | ||
|
|
b677110bd6 | ||
|
|
10768904eb | ||
|
|
263cabd1c2 | ||
|
|
4c26c3a428 | ||
|
|
e6b0b7ecc9 | ||
|
|
1024e7a3db | ||
|
|
7314f11adc | ||
|
|
30a3098095 | ||
|
|
b320e02903 | ||
|
|
0c31686fec | ||
|
|
00b69192f2 | ||
|
|
6712aa6e38 | ||
|
|
95eb2b88e6 | ||
|
|
46967f921a | ||
|
|
6b945139e0 | ||
|
|
587f94f85b | ||
|
|
1250db5075 | ||
|
|
739b4f214b | ||
|
|
ef379d0a10 | ||
|
|
66675d174b | ||
|
|
3b5825e9bc | ||
|
|
ed4f2f5e4d | ||
|
|
b89c8df35e | ||
|
|
3aa7f65240 | ||
|
|
067c3816ba | ||
|
|
efc21baeb9 | ||
|
|
ee74706c3b | ||
|
|
6e584c42c2 | ||
|
|
6621454dec | ||
|
|
adb390af4b | ||
|
|
12c95f31dc | ||
|
|
1a6d05515f | ||
|
|
1f376d8594 | ||
|
|
0bbf6081d0 | ||
|
|
ab72377ce6 | ||
|
|
f13a836972 | ||
|
|
cda92048ba | ||
|
|
15953dfed9 | ||
|
|
4ef62584da | ||
|
|
866205cba4 | ||
|
|
1ac7f36952 | ||
|
|
4cd558bdad | ||
|
|
c41687237d | ||
|
|
5036852938 | ||
|
|
4d3846e26b | ||
|
|
b01945a061 | ||
|
|
765c682c92 | ||
|
|
c484bf6ee4 | ||
|
|
9b63fccf16 | ||
|
|
420d4197f1 | ||
|
|
eaab22089d | ||
|
|
6c908fbaf1 | ||
|
|
a6c825709c | ||
|
|
eb3958f1b9 | ||
|
|
14bdedb0f7 | ||
|
|
3ec2973875 | ||
|
|
350a49cc26 | ||
|
|
9dd753f218 | ||
|
|
9a41db7d7a | ||
|
|
b80503814d | ||
|
|
5cd9b035b4 | ||
|
|
17ef758cc3 | ||
|
|
3ef92a34ee | ||
|
|
cac39b27cf | ||
|
|
7d2ed73a62 | ||
|
|
6f9b0fe712 | ||
|
|
f5c0d07a76 | ||
|
|
18c47b9e13 | ||
|
|
8cccaebc2e | ||
|
|
74f4901430 | ||
|
|
ce5a494927 | ||
|
|
228d5173ff | ||
|
|
fb7598d25a | ||
|
|
f701ee086a | ||
|
|
c1f1f84194 | ||
|
|
c1c6b6e50e | ||
|
|
c2b50c0e38 | ||
|
|
492fa86638 | ||
|
|
de8d473301 | ||
|
|
4c09fc110f | ||
|
|
293f356420 | ||
|
|
bd9e9acdaa | ||
|
|
d142824d65 | ||
|
|
8637e47219 | ||
|
|
66b0582a0b | ||
|
|
2b9311e9f1 | ||
|
|
cf544f6a85 | ||
|
|
f95a8df243 | ||
|
|
cd2bd7fa7b | ||
|
|
49fa421ba7 | ||
|
|
09c8a51348 | ||
|
|
e210b049e9 | ||
|
|
f2216b8e32 | ||
|
|
896c96134f | ||
|
|
a5efe84921 | ||
|
|
5cc8213950 | ||
|
|
5d4c048705 | ||
|
|
f637c36a7a | ||
|
|
4dae4fafe9 | ||
|
|
7a3106d659 | ||
|
|
2fa22078b8 | ||
|
|
6a65d1c515 | ||
|
|
7e7f5a6927 | ||
|
|
b3a0906619 | ||
|
|
02cf019ab6 | ||
|
|
33fcd11236 | ||
|
|
4b09baa0a0 | ||
|
|
565031f0cd | ||
|
|
b6e4a5229d | ||
|
|
f6e8da4332 | ||
|
|
232af9de6c | ||
|
|
a158053ae9 | ||
|
|
e8c87d070a | ||
|
|
56c41ae140 | ||
|
|
0b5c14962e | ||
|
|
007d17ce3f | ||
|
|
51d2384e1a | ||
|
|
87abc22cc3 | ||
|
|
9ce775f468 | ||
|
|
a6186fa486 | ||
|
|
5d93957048 | ||
|
|
5b6e42c94f | ||
|
|
c1707e920e | ||
|
|
c8df0e312a | ||
|
|
b9c0a4addc | ||
|
|
93f2af1cb3 | ||
|
|
0779d96a83 | ||
|
|
eb9964fbbb | ||
|
|
728be67afb | ||
|
|
f0b4be275f | ||
|
|
e478374e0d | ||
|
|
820fdd6348 | ||
|
|
f51a4ece6a | ||
|
|
3dec6483e7 | ||
|
|
e6a50307bb | ||
|
|
ac3bce79d1 | ||
|
|
783095a100 | ||
|
|
0965351792 | ||
|
|
dbc8aa60e3 | ||
|
|
76e8efe36e | ||
|
|
eedf51e9d1 | ||
|
|
a3f3efa1ba | ||
|
|
a70235daaa | ||
|
|
c3adc19f47 | ||
|
|
d07d83d8fc | ||
|
|
a087f6057e | ||
|
|
5498415f3b | ||
|
|
75f232eb6e | ||
|
|
38e4dfc164 | ||
|
|
afb7bc0e63 | ||
|
|
902a40ffcc | ||
|
|
3be07d842a | ||
|
|
f05acd9612 | ||
|
|
cc0a32ae87 | ||
|
|
550b5d9aea | ||
|
|
8215a32edd | ||
|
|
d912d18379 | ||
|
|
fb85d6062a | ||
|
|
c097acedd3 | ||
|
|
672681dd4b | ||
|
|
7cfec91057 | ||
|
|
51076a0be6 | ||
|
|
a90f0f50cf | ||
|
|
96e616198d | ||
|
|
866cfb9bb8 | ||
|
|
a2fce822dc | ||
|
|
c69d167fa9 | ||
|
|
99352c1e4c | ||
|
|
5bd3ec0bfb | ||
|
|
300c0376b5 | ||
|
|
db031e2b47 | ||
|
|
7b3f95d810 | ||
|
|
e75814da67 | ||
|
|
52d4e07146 | ||
|
|
92e3f667bd | ||
|
|
ea42682dbc | ||
|
|
700f32e814 | ||
|
|
c30f6cfcf1 | ||
|
|
7196c7637e | ||
|
|
48888b9034 | ||
|
|
47e4f9698c | ||
|
|
20cf73669d | ||
|
|
4b94aba6de | ||
|
|
7cd5e79464 | ||
|
|
798295a9b6 | ||
|
|
69bc077937 | ||
|
|
ef44d90c8d | ||
|
|
eeae68f9e4 | ||
|
|
925d19a8fb | ||
|
|
6fda10aed0 | ||
|
|
561f6c2d2f | ||
|
|
435610e0af | ||
|
|
38db937193 | ||
|
|
087448d167 | ||
|
|
8fa4401b20 | ||
|
|
200102580b | ||
|
|
b96aa59aef | ||
|
|
602723f894 | ||
|
|
fccb0170d4 | ||
|
|
efcbaa965e | ||
|
|
d29aa4c5ac | ||
|
|
38697234f6 | ||
|
|
a5098f1fda | ||
|
|
3b5c0b27ce | ||
|
|
4b47bee654 | ||
|
|
43d1181c04 | ||
|
|
7fe340e7bc | ||
|
|
e647428539 | ||
|
|
70eff919cd | ||
|
|
bd9f6505c1 | ||
|
|
0b8f68def0 | ||
|
|
31f3034c3a | ||
|
|
68d8cd1301 | ||
|
|
9f29bb8d9e | ||
|
|
f9c2ec8d92 | ||
|
|
6d62503e5d | ||
|
|
d8d93218fa | ||
|
|
2c5a2d07fb | ||
|
|
e01fb17d02 | ||
|
|
f070edb8b9 | ||
|
|
ac0f15379c | ||
|
|
d07f86b159 | ||
|
|
47e2999fec | ||
|
|
b549ca4517 | ||
|
|
446ffb5481 | ||
|
|
9344e9fbf7 | ||
|
|
92f7c479b9 | ||
|
|
11053afff8 | ||
|
|
e0e0b409e4 | ||
|
|
7956737ef1 | ||
|
|
a8b4e3c764 | ||
|
|
5d712e0d3f | ||
|
|
5a6030a16b | ||
|
|
ad74332a92 | ||
|
|
8a7f50889c | ||
|
|
6ee21aa365 | ||
|
|
7f9fb3a024 | ||
|
|
f16881ad16 | ||
|
|
9d4c4592fa | ||
|
|
9af1ab5f43 | ||
|
|
c4cb795081 | ||
|
|
869e7d93e0 | ||
|
|
3f71b7f1f6 | ||
|
|
35efec457c | ||
|
|
03138cb73a | ||
|
|
a6a18be089 | ||
|
|
de538deb7a | ||
|
|
f332ac1d37 | ||
|
|
3e5cb6644f | ||
|
|
2ecff76aac | ||
|
|
556efb5158 | ||
|
|
1465a7b080 | ||
|
|
d01ff8994b | ||
|
|
3f87326247 | ||
|
|
3c840102bc | ||
|
|
d63eca96e5 | ||
|
|
9dec669b94 | ||
|
|
37229df7fc | ||
|
|
85a5bfe605 | ||
|
|
4a0aadef4d | ||
|
|
a09ddfa099 | ||
|
|
ad1a0c51e2 | ||
|
|
d18f40b4e2 | ||
|
|
79f59d18f1 | ||
|
|
6fd008f23e | ||
|
|
15859d94ec | ||
|
|
d23c2b5dcc | ||
|
|
34f7eca8f7 | ||
|
|
5d8d1ed8bc | ||
|
|
73c6efdf66 | ||
|
|
cde9e5d644 | ||
|
|
a59939d295 | ||
|
|
6df259f15b | ||
|
|
d986a5adb5 | ||
|
|
f4b81ba92b | ||
|
|
899d286d2b | ||
|
|
36afdca87f | ||
|
|
5073914b86 | ||
|
|
383fbca27e | ||
|
|
12247b3f56 | ||
|
|
fc452787e7 | ||
|
|
b1c44561bb | ||
|
|
74af6351b2 | ||
|
|
8f499db4c3 | ||
|
|
42f152569d | ||
|
|
2c2174f2d0 | ||
|
|
63ab238f5d | ||
|
|
7aa263bebf | ||
|
|
077b8327ec | ||
|
|
f3273757ed | ||
|
|
457497980c | ||
|
|
74f94482cc | ||
|
|
3cf46c2def | ||
|
|
0029832ba1 | ||
|
|
9602349f30 | ||
|
|
338a93f119 | ||
|
|
db7d0e6a66 | ||
|
|
0132f350af | ||
|
|
aec9195c95 | ||
|
|
5395347582 | ||
|
|
d35dedf041 | ||
|
|
a1713bc2f9 | ||
|
|
c648a5774a | ||
|
|
3f8bfb1e98 | ||
|
|
90721375e2 | ||
|
|
d9a61c13dd | ||
|
|
5f905865be | ||
|
|
58855c2fc7 | ||
|
|
97eaeb3aec | ||
|
|
20b5f31c03 | ||
|
|
51ee524109 | ||
|
|
4045d7829b | ||
|
|
1e4c4d62e4 | ||
|
|
9ab1a3c724 | ||
|
|
570f8b21e1 | ||
|
|
429d337ef6 | ||
|
|
616434c492 | ||
|
|
137e971547 | ||
|
|
e27e873b7b | ||
|
|
c5bd98b7db | ||
|
|
2dc91cb4d5 | ||
|
|
0a0fec4a5c | ||
|
|
fb4a96ff78 | ||
|
|
346443d1b5 | ||
|
|
2ed7849921 | ||
|
|
91ae5a3585 | ||
|
|
5844697aa6 | ||
|
|
fd6bb131b8 | ||
|
|
0b6c9d7d75 | ||
|
|
1280c56f38 | ||
|
|
1ffae7cbaf | ||
|
|
789ba107cf | ||
|
|
02533c260b | ||
|
|
e0fc07df89 | ||
|
|
8e0941576f | ||
|
|
ed3ab6539d | ||
|
|
8f3d5a25a6 | ||
|
|
754e2ef1db | ||
|
|
fba0f33f1b | ||
|
|
1a4ba705f3 | ||
|
|
fc68a7d880 | ||
|
|
af7c3251cd | ||
|
|
7e24cf26de | ||
|
|
88873f7965 | ||
|
|
987ac2439a | ||
|
|
046d829e5d | ||
|
|
e3f53409f6 | ||
|
|
fa3bb8d66b | ||
|
|
723efe7cfb | ||
|
|
afddae5aaf | ||
|
|
72291875bf | ||
|
|
437cfa73ab | ||
|
|
4ed8cec7ca | ||
|
|
286f166304 | ||
|
|
b731e6ef1c | ||
|
|
438703f59e | ||
|
|
1101a40f91 | ||
|
|
66a2556525 | ||
|
|
eb1d23c0c7 | ||
|
|
0420c8c363 | ||
|
|
5d75ce2f2e | ||
|
|
f622504b5b | ||
|
|
f34ca1a7d7 | ||
|
|
a59f13b00d | ||
|
|
f2b9905b4e | ||
|
|
e2648fa3fb | ||
|
|
7e0da3e8f7 | ||
|
|
bf205fa85d | ||
|
|
9c3751a37c | ||
|
|
92b8fac94a | ||
|
|
706266d8b7 | ||
|
|
a27eb51535 | ||
|
|
a427648c48 | ||
|
|
2df9b442c6 | ||
|
|
4eea2f17d3 | ||
|
|
be5e13671c | ||
|
|
e2594f44bd | ||
|
|
40bd63f83b | ||
|
|
69b816f07c | ||
|
|
8c1ea5cb3f | ||
|
|
86108be24b | ||
|
|
edab4aaad0 | ||
|
|
1d02f2ea53 | ||
|
|
9e92455a53 | ||
|
|
299cefdc98 | ||
|
|
952dbc4b8f | ||
|
|
4d01408a46 | ||
|
|
83a0a31276 | ||
|
|
4203e8955c | ||
|
|
84e4710320 | ||
|
|
1081c104d0 | ||
|
|
feb9af48f1 | ||
|
|
32ef1f8f32 | ||
|
|
e1fa19fa7a | ||
|
|
f33f15afe8 | ||
|
|
1fe8b013ef | ||
|
|
b3057be2c9 | ||
|
|
4447c1b7e3 | ||
|
|
c3b3339e77 | ||
|
|
033938a53a | ||
|
|
b76729df1c | ||
|
|
9145bcfbb6 | ||
|
|
4396270fc7 | ||
|
|
bdb5c4ad35 | ||
|
|
3503f1ca33 | ||
|
|
52a8226edd | ||
|
|
7a05b108d5 | ||
|
|
eae275c114 | ||
|
|
2f7119e9bb | ||
|
|
f391bfed93 | ||
|
|
7177e0f698 | ||
|
|
f06c9a77b5 | ||
|
|
259d205ff6 | ||
|
|
22e88026af | ||
|
|
348ccffecd | ||
|
|
c0e2cb2919 | ||
|
|
3b38ceac2e | ||
|
|
7ee0763bc5 | ||
|
|
4b0e391bb8 | ||
|
|
e2a4d591e5 | ||
|
|
027f30610e | ||
|
|
e0f95b5d27 | ||
|
|
9de92522a6 | ||
|
|
c26e787e5d | ||
|
|
9f8db3ae54 | ||
|
|
e0d6a1cec1 | ||
|
|
f46336ae8b | ||
|
|
543d6b3209 | ||
|
|
7d5fa3f52d | ||
|
|
101d8bc9c3 | ||
|
|
74a63c004f | ||
|
|
3d869d4dec | ||
|
|
ab2eb884a0 | ||
|
|
646458d328 | ||
|
|
db73f3af20 | ||
|
|
30aef21def | ||
|
|
911bebe16c | ||
|
|
d46380e718 | ||
|
|
132b6b3efe | ||
|
|
20c69dac9e | ||
|
|
78a48b942a | ||
|
|
2434324a0c | ||
|
|
f095e51275 | ||
|
|
8c553fa8a2 | ||
|
|
328f193292 | ||
|
|
01661daf76 | ||
|
|
5b3bc28721 | ||
|
|
aaf49947e9 | ||
|
|
6db20a4be8 | ||
|
|
b4d6a6aafe | ||
|
|
c6c8366925 | ||
|
|
39cabcdd27 | ||
|
|
efc0d8557a | ||
|
|
33ffe60864 | ||
|
|
c363197275 | ||
|
|
b8072bd22e | ||
|
|
9848f82c03 | ||
|
|
8561ef5bc8 | ||
|
|
1472b46708 | ||
|
|
2e0da6a5c6 | ||
|
|
088d472662 | ||
|
|
896766ae2c | ||
|
|
016b1e0068 | ||
|
|
da05cf51de | ||
|
|
7120491d05 | ||
|
|
b4716e3b5b | ||
|
|
d1f3512aba | ||
|
|
14dd3113a2 | ||
|
|
8dae664159 | ||
|
|
9486670e93 | ||
|
|
8468e2af3a | ||
|
|
642a0d5563 | ||
|
|
95a6e01ea8 | ||
|
|
de3b7cd413 | ||
|
|
7e9f158494 | ||
|
|
89215ba6d0 | ||
|
|
410fcf7f52 | ||
|
|
2c315690f2 | ||
|
|
8526d29365 | ||
|
|
53c0012a83 | ||
|
|
29357ab556 | ||
|
|
febe71b99a | ||
|
|
5cdfa4b1af | ||
|
|
e7e8c77062 | ||
|
|
208924b929 | ||
|
|
1e26047c3b | ||
|
|
430c8d8b52 | ||
|
|
4ffe6a8282 | ||
|
|
3560827a28 | ||
|
|
c0a3d44060 | ||
|
|
5eba93d584 | ||
|
|
ed760c0397 | ||
|
|
20661c9c46 | ||
|
|
2264875237 | ||
|
|
32d2327be0 | ||
|
|
5ab3d66144 | ||
|
|
dc27f87257 | ||
|
|
4f0eeaa55e | ||
|
|
5cb60ffbe0 | ||
|
|
fe983b1309 | ||
|
|
0628d85a6a | ||
|
|
a195e94e88 | ||
|
|
6e451d4f33 | ||
|
|
b5ac234771 | ||
|
|
e145231a1d | ||
|
|
ed0cb19909 | ||
|
|
dc9e17503e | ||
|
|
6577093d2d | ||
|
|
0b4805f366 | ||
|
|
ee520689d7 | ||
|
|
944b4685b9 | ||
|
|
d1284ff33d | ||
|
|
68b7779bc7 | ||
|
|
5dcfa97fb9 | ||
|
|
387b7d857d | ||
|
|
f59e502382 | ||
|
|
5bf395040f | ||
|
|
f91a34c9e6 | ||
|
|
0d193a446b | ||
|
|
b3d759ca6d | ||
|
|
2dcbc6493a | ||
|
|
f10a23e669 | ||
|
|
0a953de3a8 | ||
|
|
4855055bca | ||
|
|
9035d15ed2 | ||
|
|
936c71df70 | ||
|
|
b893bd074f | ||
|
|
e469bdb6fa | ||
|
|
3a494f5d8d | ||
|
|
c3e7a970c6 | ||
|
|
d0f7db0828 | ||
|
|
cd1f96d421 | ||
|
|
98cf1c412a | ||
|
|
80377c20f9 | ||
|
|
619356dd08 | ||
|
|
fb810e25c4 | ||
|
|
a3163aa2cf | ||
|
|
220e20e7f2 | ||
|
|
c9d6e04636 | ||
|
|
f279d465d0 | ||
|
|
aeca551f5b | ||
|
|
a068aaed3c | ||
|
|
d037aec415 | ||
|
|
4cea15d274 | ||
|
|
38eb67de83 | ||
|
|
1a6742e651 | ||
|
|
d77370694c | ||
|
|
b5965d05a2 | ||
|
|
31dd66acbf | ||
|
|
0ff1ba0a6d | ||
|
|
4cda0861f5 | ||
|
|
27ec76dd3a | ||
|
|
9061b8961e | ||
|
|
7a93a5f18e | ||
|
|
7b1ebe896c | ||
|
|
45f9c5b942 | ||
|
|
993cdb82b6 | ||
|
|
f73cec7f01 | ||
|
|
eb72857ea2 | ||
|
|
528f972d17 | ||
|
|
471c0aa634 | ||
|
|
526f9da463 | ||
|
|
f8206cb357 | ||
|
|
2a1f8baac4 | ||
|
|
78123520a9 | ||
|
|
0663c883e5 | ||
|
|
6901a8cb13 | ||
|
|
4330c986db | ||
|
|
be45263623 | ||
|
|
b4e25a6372 | ||
|
|
4013fc56a3 | ||
|
|
b51858159a | ||
|
|
ed8289e2c5 | ||
|
|
0eb0a887d8 | ||
|
|
ea92682b98 | ||
|
|
9df232911c | ||
|
|
6ea538cec3 | ||
|
|
53752ccaab | ||
|
|
09b6b94509 | ||
|
|
f5023ac544 | ||
|
|
f695bb0b6f | ||
|
|
8231deffd0 | ||
|
|
4f16e627ba | ||
|
|
7832f25abf | ||
|
|
6fbc96fec4 | ||
|
|
a352109ade | ||
|
|
b27aae4bf9 | ||
|
|
129e72de70 | ||
|
|
a74a93d885 | ||
|
|
01e43fbe83 | ||
|
|
3f502123ea | ||
|
|
f8272eba94 | ||
|
|
314e526f75 | ||
|
|
d94a870de4 | ||
|
|
199c4d21bd | ||
|
|
ca12bf76f5 | ||
|
|
3d18053370 | ||
|
|
eb4f012239 | ||
|
|
b4df3cade6 | ||
|
|
acd285e00f | ||
|
|
7d06489712 | ||
|
|
229d83f6c6 | ||
|
|
6a9baf3fd7 | ||
|
|
5659a1662e | ||
|
|
52d1a637b9 | ||
|
|
b753edec1d | ||
|
|
f103cb4538 | ||
|
|
2555e500b6 | ||
|
|
5ce369ad46 | ||
|
|
98defd5a56 | ||
|
|
f9861e1fab | ||
|
|
67e9f2861e | ||
|
|
4c7098e362 | ||
|
|
8f2efd0b16 | ||
|
|
2c1c5f7a13 | ||
|
|
fd6f806194 | ||
|
|
b226c8ca79 | ||
|
|
96529063bf | ||
|
|
9bf32ff72d | ||
|
|
3d8b883c15 | ||
|
|
90d25919f3 | ||
|
|
bb365ca424 | ||
|
|
eaf4da0411 | ||
|
|
27215e89f9 | ||
|
|
ac474a2812 | ||
|
|
cb1a278e00 | ||
|
|
b700e0d2f8 | ||
|
|
ace919a0cd | ||
|
|
422327c010 | ||
|
|
a943905d6c | ||
|
|
f857a842fc | ||
|
|
1a792d46d0 | ||
|
|
7a2fad1e35 | ||
|
|
30f1877135 | ||
|
|
2f0671eb79 | ||
|
|
ab31ad2704 | ||
|
|
becd55dced | ||
|
|
e1c2aa2ddd | ||
|
|
d7c8b3ad06 | ||
|
|
a0b82db402 | ||
|
|
c085a1b4f0 | ||
|
|
9bfcdc40ef | ||
|
|
e3ecc328a1 | ||
|
|
8b5aa221ad | ||
|
|
83584bf889 | ||
|
|
367abca382 | ||
|
|
c11398ea0d | ||
|
|
05d12897a2 | ||
|
|
f1e789bfc2 | ||
|
|
51672aef72 | ||
|
|
9de3bc8ef6 | ||
|
|
823cb494a5 | ||
|
|
1e2ec3642d | ||
|
|
0a851c869f | ||
|
|
596496f695 | ||
|
|
4d86b8a83c | ||
|
|
c6d428d47d | ||
|
|
275c7ccf82 | ||
|
|
138db5a85d | ||
|
|
f659b6a0d9 | ||
|
|
db19b18241 | ||
|
|
094d7fd4b1 | ||
|
|
f05ac0cb23 | ||
|
|
ff1273a312 | ||
|
|
827dc054fb | ||
|
|
0ade885617 | ||
|
|
40b379859c | ||
|
|
891f871ba7 | ||
|
|
6fa72c5d9d | ||
|
|
73aba23a49 | ||
|
|
6a04757e6d | ||
|
|
6082595e96 | ||
|
|
c8c8d2035a | ||
|
|
0ce885e8c8 | ||
|
|
c57103f2d8 | ||
|
|
39da6979ad | ||
|
|
f2b9af6ae1 | ||
|
|
a95c0608b9 | ||
|
|
e7f0544154 | ||
|
|
6825a69a70 | ||
|
|
62ed6b0aaf | ||
|
|
8087f51d14 | ||
|
|
0464a1071e | ||
|
|
023bd63d39 | ||
|
|
b5d833b329 | ||
|
|
9c6de08db0 | ||
|
|
84bd794588 | ||
|
|
b40ab4dc9e | ||
|
|
1161482ec2 | ||
|
|
e698d6255b | ||
|
|
6cc06cd35d | ||
|
|
4d9b2f671a | ||
|
|
cf689f7472 | ||
|
|
74c24f3e6d | ||
|
|
0c133b3f02 | ||
|
|
8710118b2c | ||
|
|
a17076cf4f | ||
|
|
7056ceda67 | ||
|
|
1ad1980f1f | ||
|
|
5f943cf4bc | ||
|
|
01ccb52a00 | ||
|
|
52b00630c8 | ||
|
|
9cc23118be | ||
|
|
dc33638cb2 | ||
|
|
bdeaee4a33 | ||
|
|
28d9398de7 | ||
|
|
c934a33ccd | ||
|
|
89086a8e19 | ||
|
|
6378fbd66e | ||
|
|
03577bc936 | ||
|
|
18033026cb | ||
|
|
037a1a3e0f | ||
|
|
56d75bd23b | ||
|
|
8682ed9bd0 | ||
|
|
fee2a7ecfa | ||
|
|
b7b19348a7 | ||
|
|
64cf8d3893 | ||
|
|
a8c8a85135 | ||
|
|
cf38d635bf | ||
|
|
3940bd5b84 | ||
|
|
6f1fc1b5ba | ||
|
|
ca3a4ce672 | ||
|
|
4980ef85e2 | ||
|
|
b01d9b6181 | ||
|
|
3e79e9f981 | ||
|
|
8b933e470e | ||
|
|
c6d0611112 | ||
|
|
a453d8d64d | ||
|
|
cefa16ae77 | ||
|
|
fc858927f0 | ||
|
|
f760bc243b | ||
|
|
ea54aa386c | ||
|
|
19eeb3556e | ||
|
|
6ddd4e6a3f | ||
|
|
dfb5cb3c5d | ||
|
|
f127bc387a | ||
|
|
50403afb5c | ||
|
|
d53f313599 | ||
|
|
1633e22aec | ||
|
|
d18c82a9ef | ||
|
|
db027faf38 | ||
|
|
a294d45fd6 | ||
|
|
288cd05f89 | ||
|
|
5dfc0d0d19 | ||
|
|
06b3852143 | ||
|
|
aefa0da8a6 | ||
|
|
ee9aee6c00 | ||
|
|
5c32156a71 | ||
|
|
0ec9e3aeb7 | ||
|
|
015b814e6a | ||
|
|
201e4d2835 | ||
|
|
8ac7bda244 | ||
|
|
30bb68d48a | ||
|
|
ec86d5db0f | ||
|
|
9589acd00e | ||
|
|
3ae6043e7e | ||
|
|
3ab4b3d58f | ||
|
|
c96a4406e4 | ||
|
|
731c6f9083 | ||
|
|
347de6b08c | ||
|
|
805959378d | ||
|
|
e5be2e9f97 | ||
|
|
e6cedc2b8c | ||
|
|
d640121ce6 | ||
|
|
fd2a808266 | ||
|
|
28ad262a46 | ||
|
|
6810a0e3e3 | ||
|
|
d6d665b0c0 | ||
|
|
ef975d277a | ||
|
|
7c2fcd4ad9 | ||
|
|
e1db8d11ad | ||
|
|
c5c6ef6e2b | ||
|
|
e33af13ae3 | ||
|
|
27b7ecbbff | ||
|
|
fca23d1675 | ||
|
|
1c46fdf600 | ||
|
|
698eac2a94 | ||
|
|
854a000b44 | ||
|
|
05108cf81c | ||
|
|
f3a2eec13b | ||
|
|
e360d048ba | ||
|
|
a59874e312 | ||
|
|
02c86567ee | ||
|
|
2c3d1fa954 | ||
|
|
6912463585 | ||
|
|
97810e1850 | ||
|
|
3e0899359b | ||
|
|
bdbf0f863d | ||
|
|
9acdf94cc0 | ||
|
|
8ac68a4d94 | ||
|
|
b1d4dfa6b1 | ||
|
|
f9426bfcd5 | ||
|
|
b403b41aec | ||
|
|
b30e237a37 | ||
|
|
325c167e2a | ||
|
|
84534ce4b8 | ||
|
|
aa88e150da | ||
|
|
55bcd0ba1e | ||
|
|
e7be3d873f | ||
|
|
c0b78276e8 | ||
|
|
68cfb25c11 | ||
|
|
bfbdb1f028 | ||
|
|
1e3934e464 | ||
|
|
a932d201d2 | ||
|
|
6e4dfc8eb5 | ||
|
|
f3b4240b87 | ||
|
|
0226cca832 | ||
|
|
2c2ae2adb2 | ||
|
|
952f560d0a | ||
|
|
2ee228d5d1 | ||
|
|
ec6e267351 | ||
|
|
67cea2b9b5 | ||
|
|
b5811cc73c | ||
|
|
02ca9e3b59 | ||
|
|
1af2d94860 | ||
|
|
172945de31 | ||
|
|
f54cb2e323 | ||
|
|
3c9864c9d3 | ||
|
|
dbb87bc557 | ||
|
|
6feedc9cff | ||
|
|
bd1c878af4 | ||
|
|
f841447c75 | ||
|
|
54df6a30c5 | ||
|
|
f74e296f84 | ||
|
|
5a18100816 | ||
|
|
0d2f8d5079 | ||
|
|
127253c8d5 | ||
|
|
2f0f1d0a3f | ||
|
|
baf4f8c9eb | ||
|
|
383d047763 | ||
|
|
4ed44fc634 | ||
|
|
9e649ffdf2 | ||
|
|
9b76435280 | ||
|
|
b22af9776d | ||
|
|
4583c4ea0a | ||
|
|
e5ed6aec0e | ||
|
|
65b899030d | ||
|
|
6bab7a5bda | ||
|
|
ebd45529c1 | ||
|
|
c61488cf9d | ||
|
|
72ec035eba | ||
|
|
a080277f84 | ||
|
|
37b660dd78 | ||
|
|
dd60372226 | ||
|
|
ce1399db2d | ||
|
|
2cae55ae04 | ||
|
|
3e4dec3cf4 | ||
|
|
d1a90c6ec6 | ||
|
|
b5946751b8 | ||
|
|
bfca977d5f | ||
|
|
c1155cd2a5 | ||
|
|
85dbc2d306 | ||
|
|
f7f1408168 | ||
|
|
0c18e05336 | ||
|
|
cb3915c5e1 | ||
|
|
dfe195a4a1 | ||
|
|
9b4be8a739 | ||
|
|
6c8e740b57 | ||
|
|
30f8568570 | ||
|
|
1a5e30b053 | ||
|
|
52851b722d | ||
|
|
651103ff32 | ||
|
|
1bdc0d1dd3 | ||
|
|
43de61f37b | ||
|
|
117a77e106 | ||
|
|
8f0d0250cd | ||
|
|
7b946ec025 | ||
|
|
693d019654 | ||
|
|
93158a53a8 | ||
|
|
a8542fbe06 | ||
|
|
976d5b18ed | ||
|
|
2ca05eeb16 | ||
|
|
df8e151408 | ||
|
|
86d64b2f5e | ||
|
|
b6f2902905 | ||
|
|
83876b1b81 | ||
|
|
139562cc64 | ||
|
|
6d7ad66982 | ||
|
|
a9f2c3ffaf | ||
|
|
e599fdd60d | ||
|
|
8d4f5038d0 | ||
|
|
ed56b8c173 | ||
|
|
82ceca0717 | ||
|
|
3ff572ffcd | ||
|
|
a674c039fb | ||
|
|
9686d92bfc | ||
|
|
5d3b5eb700 | ||
|
|
bacb20a379 | ||
|
|
9540a93d95 | ||
|
|
317675d5e5 | ||
|
|
d23d14897a | ||
|
|
2bb4a853ec | ||
|
|
a1e823b038 | ||
|
|
705e8e929a | ||
|
|
579d0f6f41 | ||
|
|
4c7607e074 | ||
|
|
5b1caed806 | ||
|
|
a1da2b713b | ||
|
|
1f8c5c37d3 | ||
|
|
25f45cace1 | ||
|
|
b15f585273 | ||
|
|
d2def332fd | ||
|
|
d18d6ba019 | ||
|
|
1dfea2a362 | ||
|
|
ff1d68c50b | ||
|
|
2464da5b26 | ||
|
|
d4c91bbd85 | ||
|
|
b1f4ade874 | ||
|
|
0097305953 | ||
|
|
b4ea608b65 | ||
|
|
28041461b7 | ||
|
|
10c441deed | ||
|
|
41c51a11d3 | ||
|
|
38faa64b12 | ||
|
|
c156f2d493 | ||
|
|
fe18117fb2 | ||
|
|
b0ba4caf64 | ||
|
|
c7a4412f8a | ||
|
|
281424dded | ||
|
|
b7a4a9a6ce | ||
|
|
d8f349f201 | ||
|
|
6cafb2619a | ||
|
|
8f97f3180a | ||
|
|
be4fd48ab8 | ||
|
|
c5e07af902 | ||
|
|
0696ab09b1 | ||
|
|
3f35e2d39e | ||
|
|
23ef565a3c | ||
|
|
07d19df80f | ||
|
|
05c2d9bd73 | ||
|
|
19a36c9acb | ||
|
|
a7e70e6229 | ||
|
|
1bbabd1e81 | ||
|
|
97eb4bd0ff | ||
|
|
b0e7170965 | ||
|
|
27ebd3ce2e | ||
|
|
0d333fdcb4 | ||
|
|
f11a3b2324 | ||
|
|
1d813167c4 | ||
|
|
8f76092b89 | ||
|
|
9b0e03cb2e | ||
|
|
298f546be0 | ||
|
|
18725aab28 | ||
|
|
2793170fed | ||
|
|
b92c87e2ec | ||
|
|
ce378d8984 | ||
|
|
9604df8431 | ||
|
|
463267ce12 | ||
|
|
05f0444c02 | ||
|
|
516e0cb71a | ||
|
|
7ea77d93e3 | ||
|
|
4255eb511e | ||
|
|
2aaa8f7909 | ||
|
|
f7c0cc976d | ||
|
|
2f5d5e3ba7 | ||
|
|
b487ebaaba | ||
|
|
b767f34b6b | ||
|
|
7d6556ffe7 | ||
|
|
b3ac785f95 | ||
|
|
865a43050d | ||
|
|
dcff5571a2 | ||
|
|
4308f32255 | ||
|
|
fa062ca0c4 | ||
|
|
e56fdfc4be | ||
|
|
2ec3e6b49e | ||
|
|
ddedefd4c4 | ||
|
|
7d58b9247e | ||
|
|
24955f8358 | ||
|
|
1c6ce881ec | ||
|
|
8c211113f2 | ||
|
|
a8ba628bcd | ||
|
|
75c586bbe1 | ||
|
|
ede5ce9ac1 | ||
|
|
b7ea4a7e65 | ||
|
|
0662ec4a43 | ||
|
|
e3f93241c3 | ||
|
|
9c45e33d8c | ||
|
|
d11cf5d191 | ||
|
|
c67abd7e61 | ||
|
|
e1b668c868 | ||
|
|
65d3e51650 | ||
|
|
66653e8f14 | ||
|
|
911e6e710f | ||
|
|
4ae4005f80 | ||
|
|
d5fffc032f | ||
|
|
d82a032566 | ||
|
|
46813bbe4e | ||
|
|
bfff1ac8b2 | ||
|
|
aea27a7ce4 | ||
|
|
420789c278 | ||
|
|
7fccdedcb5 | ||
|
|
c093139494 | ||
|
|
0715496d72 | ||
|
|
ca02dfab48 | ||
|
|
da93b591e2 | ||
|
|
d9185a9580 | ||
|
|
f9641790b5 | ||
|
|
3001ed54f9 | ||
|
|
4e3ac4319b | ||
|
|
7a744fcb17 | ||
|
|
72457052fc | ||
|
|
1284a34fc3 | ||
|
|
515a5a4444 | ||
|
|
834efe018a | ||
|
|
f72fdf44f6 | ||
|
|
42dde41241 | ||
|
|
9fd21ba2db | ||
|
|
d6a642e064 | ||
|
|
b597855d6f | ||
|
|
e3c3130488 | ||
|
|
959adc6218 | ||
|
|
51c6356ea7 | ||
|
|
064df34ae4 | ||
|
|
886a1ab15d |
405
.gitignore
vendored
405
.gitignore
vendored
@@ -58,12 +58,16 @@ examples/cross_calculator/android/tags
|
||||
# Generated files.
|
||||
/compile.json
|
||||
/compiler/c2nim/c2nim
|
||||
/compiler/nimrod.dot
|
||||
/compiler/pas2nim/pas2nim
|
||||
/compiler/service
|
||||
/examples/allany
|
||||
/examples/cairoex
|
||||
/examples/cgiex
|
||||
/examples/cgi/cgi_stacktrace
|
||||
/examples/cgi/example
|
||||
/examples/curlex
|
||||
/examples/debugging
|
||||
/examples/docstrings
|
||||
/examples/filterex
|
||||
/examples/fizzbuzz
|
||||
@@ -89,6 +93,12 @@ examples/cross_calculator/android/tags
|
||||
/examples/pythonex
|
||||
/examples/sdlex
|
||||
/examples/statcsv
|
||||
/examples/talk/dsl
|
||||
/examples/talk/formatoptimizer
|
||||
/examples/talk/hoisting
|
||||
/examples/talk/lazyeval
|
||||
/examples/talk/quasiquote
|
||||
/examples/talk/tags
|
||||
/examples/tclex
|
||||
/examples/transff
|
||||
/examples/tunit
|
||||
@@ -96,10 +106,13 @@ examples/cross_calculator/android/tags
|
||||
/examples/x11ex
|
||||
/lib/libnimrtl.dylib
|
||||
/lib/libserver.dylib
|
||||
/lib/packages/docutils/highlite
|
||||
/lib/pure/actors
|
||||
/lib/pure/algorithm
|
||||
/lib/pure/asyncio
|
||||
/lib/pure/base64
|
||||
/lib/pure/basic2d
|
||||
/lib/pure/basic3d
|
||||
/lib/pure/browsers
|
||||
/lib/pure/cgi
|
||||
/lib/pure/collections/sequtils
|
||||
@@ -111,6 +124,7 @@ examples/cross_calculator/android/tags
|
||||
/lib/pure/encodings
|
||||
/lib/pure/endians
|
||||
/lib/pure/events
|
||||
/lib/pure/fsmonitor
|
||||
/lib/pure/ftpclient
|
||||
/lib/pure/gentabs
|
||||
/lib/pure/hashes
|
||||
@@ -127,19 +141,23 @@ examples/cross_calculator/android/tags
|
||||
/lib/pure/math
|
||||
/lib/pure/md5
|
||||
/lib/pure/memfiles
|
||||
/lib/pure/mersenne
|
||||
/lib/pure/mimetypes
|
||||
/lib/pure/nimprof
|
||||
/lib/pure/numeric
|
||||
/lib/pure/oids
|
||||
/lib/pure/os
|
||||
/lib/pure/osproc
|
||||
/lib/pure/parsecfg
|
||||
/lib/pure/parsecsv
|
||||
/lib/pure/parseopt
|
||||
/lib/pure/parseopt2
|
||||
/lib/pure/parsesql
|
||||
/lib/pure/parseurl
|
||||
/lib/pure/parseutils
|
||||
/lib/pure/parsexml
|
||||
/lib/pure/pegs
|
||||
/lib/pure/poly
|
||||
/lib/pure/redis
|
||||
/lib/pure/romans
|
||||
/lib/pure/ropes
|
||||
@@ -167,4 +185,391 @@ examples/cross_calculator/android/tags
|
||||
/run.json
|
||||
/testresults.html
|
||||
/testresults.json
|
||||
/tests/caas/absurd_nesting
|
||||
/tests/caas/completion_dot_syntax_main
|
||||
/tests/caasdriver
|
||||
/tests/caas/forward_declarations
|
||||
/tests/caas/idetools_api
|
||||
/tests/caas/imported
|
||||
/tests/caas/issue_416_template_shift
|
||||
/tests/caas/issue_452_export_shift
|
||||
/tests/caas/issue_477_dynamic_dispatch
|
||||
/tests/caas/its_full_of_procs
|
||||
/tests/caas/main
|
||||
/tests/caas/SymbolProcRun.*/
|
||||
/tests/ccg/tmissingbracket
|
||||
/tests/compile/talias
|
||||
/tests/compile/tambsym2
|
||||
/tests/compile/tarrindx
|
||||
/tests/compile/tassign
|
||||
/tests/compile/tbindoverload
|
||||
/tests/compile/tcan_alias_generic
|
||||
/tests/compile/tcan_alias_specialised_generic
|
||||
/tests/compile/tcan_inherit_generic
|
||||
/tests/compile/tcan_specialise_generic
|
||||
/tests/compile/tccgen1
|
||||
/tests/compile/tclosure4
|
||||
/tests/compile/tclosurebug2
|
||||
/tests/compile/tcmdline
|
||||
/tests/compile/tcodegenbug1
|
||||
/tests/compile/tcolonisproc
|
||||
/tests/compile/tcolors
|
||||
/tests/compile/tcommontype
|
||||
/tests/compile/tcompiles
|
||||
/tests/compile/tcomputedgoto
|
||||
/tests/compile/tconsteval
|
||||
/tests/compile/tconstraints
|
||||
/tests/compile/tconvcolors
|
||||
/tests/compile/tcputime
|
||||
/tests/compile/tdefaultprocparam
|
||||
/tests/compile/tdictdestruct
|
||||
/tests/compile/tdiscardable
|
||||
/tests/compile/tdllvar
|
||||
/tests/compile/tdumpast
|
||||
/tests/compile/tdumpast2
|
||||
/tests/compile/techo
|
||||
/tests/compile/teffects1
|
||||
/tests/compile/temptyecho
|
||||
/tests/compile/tendian
|
||||
/tests/compile/tenum
|
||||
/tests/compile/tenum2
|
||||
/tests/compile/tenum3
|
||||
/tests/compile/teval1
|
||||
/tests/compile/texport
|
||||
/tests/compile/tfib
|
||||
/tests/compile/tforwardgeneric
|
||||
/tests/compile/tforwty
|
||||
/tests/compile/tforwty2
|
||||
/tests/compile/tgeneric
|
||||
/tests/compile/tgeneric2
|
||||
/tests/compile/tgeneric3
|
||||
/tests/compile/tgeneric4
|
||||
/tests/compile/tgenericmatcher
|
||||
/tests/compile/tgenericmatcher2
|
||||
/tests/compile/tgenericprocvar
|
||||
/tests/compile/tgenericprop
|
||||
/tests/compile/tgenericrefs
|
||||
/tests/compile/tgenerictmpl
|
||||
/tests/compile/tgenericvariant
|
||||
/tests/compile/tgensymgeneric
|
||||
/tests/compile/tgetstartmilsecs
|
||||
/tests/compile/tglobalforvar
|
||||
/tests/compile/thallo
|
||||
/tests/compile/theaproots
|
||||
/tests/compile/thexrange
|
||||
/tests/compile/thygienictempl
|
||||
/tests/compile/tident
|
||||
/tests/compile/timplicititems
|
||||
/tests/compile/timplictderef
|
||||
/tests/compile/tinheritref
|
||||
/tests/compile/tio
|
||||
/tests/compile/tircbot
|
||||
/tests/compile/titer
|
||||
/tests/compile/titer2
|
||||
/tests/compile/titer_no_tuple_unpack
|
||||
/tests/compile/titerovl
|
||||
/tests/compile/tlastmod
|
||||
/tests/compile/tlinearscanend
|
||||
/tests/compile/tloops
|
||||
/tests/compile/tmacro1
|
||||
/tests/compile/tmacro2
|
||||
/tests/compile/tmacroaspragma
|
||||
/tests/compile/tmacrostmt
|
||||
/tests/compile/tmandelbrot
|
||||
/tests/compile/tmarshal
|
||||
/tests/compile/tmath
|
||||
/tests/compile/tmatrix1
|
||||
/tests/compile/tmatrix2
|
||||
/tests/compile/tmongo
|
||||
/tests/compile/tnamedparamanonproc
|
||||
/tests/compile/tnamedparams
|
||||
/tests/compile/tnestedproc
|
||||
/tests/compile/tnew
|
||||
/tests/compile/tnewsets
|
||||
/tests/compile/tnewuns
|
||||
/tests/compile/tnoargopenarray
|
||||
/tests/compile/tnoforward
|
||||
/tests/compile/tobjconstr2
|
||||
/tests/compile/tobjcov
|
||||
/tests/compile/tobject2
|
||||
/tests/compile/tobject3
|
||||
/tests/compile/tobjects
|
||||
/tests/compile/toop
|
||||
/tests/compile/toptions
|
||||
/tests/compile/tos
|
||||
/tests/compile/toverprc
|
||||
/tests/compile/tparedef
|
||||
/tests/compile/tparscfg
|
||||
/tests/compile/tparsefloat
|
||||
/tests/compile/tparsopt
|
||||
/tests/compile/tposix
|
||||
/tests/compile/tprep
|
||||
/tests/compile/tprocvars
|
||||
/tests/compile/tpush
|
||||
/tests/compile/tquicksort
|
||||
/tests/compile/tquit
|
||||
/tests/compile/tradix
|
||||
/tests/compile/treadln
|
||||
/tests/compile/treadx
|
||||
/tests/compile/trecmod
|
||||
/tests/compile/trecmod2
|
||||
/tests/compile/trectuple
|
||||
/tests/compile/trectuples
|
||||
/tests/compile/tredef
|
||||
/tests/compile/trepr
|
||||
/tests/compile/tsecondarrayproperty
|
||||
/tests/compile/tseq2
|
||||
/tests/compile/tseqcon2
|
||||
/tests/compile/tshadow_magic_type
|
||||
/tests/compile/tsizeof
|
||||
/tests/compile/tslurp
|
||||
/tests/compile/tsockets
|
||||
/tests/compile/tsortcall
|
||||
/tests/compile/tspecialised_is_equivalent
|
||||
/tests/compile/tstrace
|
||||
/tests/compile/tstrdesc
|
||||
/tests/compile/tstrdist
|
||||
/tests/compile/tstreams
|
||||
/tests/compile/tstrset
|
||||
/tests/compile/tstrtabs
|
||||
/tests/compile/ttableconstr
|
||||
/tests/compile/ttempl
|
||||
/tests/compile/ttempl3
|
||||
/tests/compile/ttempl4
|
||||
/tests/compile/ttempl5
|
||||
/tests/compile/ttemplreturntype
|
||||
/tests/compile/tthread_generic
|
||||
/tests/compile/ttime
|
||||
/tests/compile/ttuple1
|
||||
/tests/compile/ttypeclasses
|
||||
/tests/compile/ttypeconverter1
|
||||
/tests/compile/tuserpragma
|
||||
/tests/compile/tvoid
|
||||
/tests/compile/twalker
|
||||
/tests/compile/typalias
|
||||
/tests/dll/client
|
||||
/tests/gc/closureleak
|
||||
/tests/gc/cycleleak
|
||||
/tests/gc/gcbench
|
||||
/tests/gc/gcleak
|
||||
/tests/gc/gcleak2
|
||||
/tests/gc/gcleak3
|
||||
/tests/gc/gctest
|
||||
/tests/gc/weakrefs
|
||||
/tests/manyloc/argument_parser/ex_wget
|
||||
/tests/manyloc/nake/nakefile
|
||||
/tests/manyloc/packages/noconflicts
|
||||
/tests/manyloc/standalone/barebone
|
||||
/tests/patterns/targlist
|
||||
/tests/patterns/tcse
|
||||
/tests/patterns/thoist
|
||||
/tests/patterns/tmatrix
|
||||
/tests/patterns/tnoalias
|
||||
/tests/patterns/tnoendlessrec
|
||||
/tests/patterns/tor
|
||||
/tests/patterns/tpartial
|
||||
/tests/patterns/tstar
|
||||
/tests/patterns/tstmtlist
|
||||
/tests/reject/t99bott
|
||||
/tests/reject/tcheckedfield1
|
||||
/tests/reject/tdeprecated
|
||||
/tests/reject/tdisallowif
|
||||
/tests/reject/tuninit1
|
||||
/tests/rodfiles/aconv
|
||||
/tests/rodfiles/bconv
|
||||
/tests/rodfiles/bmethods
|
||||
/tests/rodfiles/bmethods2
|
||||
/tests/rodfiles/deada
|
||||
/tests/rodfiles/deada2
|
||||
/tests/rodfiles/hallo
|
||||
/tests/rodfiles/hallo2
|
||||
/tests/rodfiles/tgeneric1
|
||||
/tests/rodfiles/tgeneric2
|
||||
/tests/run/tack
|
||||
/tests/run/tactiontable
|
||||
/tests/run/tambsym2
|
||||
/tests/run/tambsys
|
||||
/tests/run/tanontuples
|
||||
/tests/run/tarray
|
||||
/tests/run/tarray2
|
||||
/tests/run/tarray3
|
||||
/tests/run/tarraycons
|
||||
/tests/run/tassert
|
||||
/tests/run/tastoverload1
|
||||
/tests/run/tasynciossl
|
||||
/tests/run/tasyncudp
|
||||
/tests/run/tbind1
|
||||
/tests/run/tbind3
|
||||
/tests/run/tbintre2
|
||||
/tests/run/tbintree
|
||||
/tests/run/tborrow
|
||||
/tests/run/tbug499771
|
||||
/tests/run/tbug511622
|
||||
/tests/run/tcase_setconstr
|
||||
/tests/run/tcasestm
|
||||
/tests/run/tcgbug
|
||||
/tests/run/tclosure2
|
||||
/tests/run/tclosure3
|
||||
/tests/run/tcnstseq
|
||||
/tests/run/tcnstseq2
|
||||
/tests/run/tcnstseq3
|
||||
/tests/run/tconcat
|
||||
/tests/run/tconstr2
|
||||
/tests/run/tcontinue
|
||||
/tests/run/tcontinuexc
|
||||
/tests/run/tcopy
|
||||
/tests/run/tcountup
|
||||
/tests/run/tcritbits
|
||||
/tests/run/tcurrncy
|
||||
/tests/run/tdestructor
|
||||
/tests/run/tdrdobbs_examples
|
||||
/tests/run/temit
|
||||
/tests/run/tenumhole
|
||||
/tests/run/tenumitems
|
||||
/tests/run/teventemitter
|
||||
/tests/run/tevents
|
||||
/tests/run/texceptions
|
||||
/tests/run/texcpt1
|
||||
/tests/run/texcsub
|
||||
/tests/run/texplicitgeneric1
|
||||
/tests/run/tfieldindex
|
||||
/tests/run/tfielditerator
|
||||
/tests/run/tfielditerator2
|
||||
/tests/run/tfilter
|
||||
/tests/run/tfinally
|
||||
/tests/run/tfinally2
|
||||
/tests/run/tfinally3
|
||||
/tests/run/tfinalobj
|
||||
/tests/run/tfloat1
|
||||
/tests/run/tfloat2
|
||||
/tests/run/tfloat3
|
||||
/tests/run/tformat
|
||||
/tests/run/tfriends
|
||||
/tests/run/tgenericassign
|
||||
/tests/run/tgenericassigntuples
|
||||
/tests/run/tgenericconverter
|
||||
/tests/run/tgenericprocvar
|
||||
/tests/run/tgenerics1
|
||||
/tests/run/tgensym
|
||||
/tests/run/tglobal
|
||||
/tests/run/thashes
|
||||
/tests/run/thexlit
|
||||
/tests/run/thintoff
|
||||
/tests/run/tidgen
|
||||
/tests/run/tindent1
|
||||
/tests/run/tinit
|
||||
/tests/run/tinterf
|
||||
/tests/run/tints
|
||||
/tests/run/tisopr
|
||||
/tests/run/titer3
|
||||
/tests/run/titer5
|
||||
/tests/run/titer6
|
||||
/tests/run/titer7
|
||||
/tests/run/titer8
|
||||
/tests/run/titer9
|
||||
/tests/run/titerslice
|
||||
/tests/run/titervaropenarray
|
||||
/tests/run/tkoeniglookup
|
||||
/tests/run/tlet
|
||||
/tests/run/tlists
|
||||
/tests/run/tlocals
|
||||
/tests/run/tlowhigh
|
||||
/tests/run/tmacro2
|
||||
/tests/run/tmacro3
|
||||
/tests/run/tmacro4
|
||||
/tests/run/tmacros1
|
||||
/tests/run/tmath
|
||||
/tests/run/tmatrix
|
||||
/tests/run/tmemoization
|
||||
/tests/run/tmethods1
|
||||
/tests/run/tmixin
|
||||
/tests/run/tmoditer
|
||||
/tests/run/tmultim1
|
||||
/tests/run/tmultim2
|
||||
/tests/run/tmultim3
|
||||
/tests/run/tmultim4
|
||||
/tests/run/tmultim6
|
||||
/tests/run/tnamedenumfields
|
||||
/tests/run/tnestif
|
||||
/tests/run/tnestprc
|
||||
/tests/run/tnewderef
|
||||
/tests/run/tnodeadlocks
|
||||
/tests/run/tobjasgn
|
||||
/tests/run/tobjconstr
|
||||
/tests/run/tobject
|
||||
/tests/run/tofopr
|
||||
/tests/run/tonraise
|
||||
/tests/run/toop1
|
||||
/tests/run/topenarrayrepr
|
||||
/tests/run/topenlen
|
||||
/tests/run/toprprec
|
||||
/tests/run/toverflw
|
||||
/tests/run/toverflw2
|
||||
/tests/run/toverl2
|
||||
/tests/run/toverl3
|
||||
/tests/run/toverwr
|
||||
/tests/run/tovfint
|
||||
/tests/run/tpatterns
|
||||
/tests/run/tpegs
|
||||
/tests/run/tpos
|
||||
/tests/run/tprecedence
|
||||
/tests/run/tprintf
|
||||
/tests/run/tprocvar
|
||||
/tests/run/tquotewords
|
||||
/tests/run/tregex
|
||||
/tests/run/treguse
|
||||
/tests/run/trepr
|
||||
/tests/run/treraise
|
||||
/tests/run/tromans
|
||||
/tests/run/tseqcon
|
||||
/tests/run/tseqtuple
|
||||
/tests/run/tsequtils
|
||||
/tests/run/tsets
|
||||
/tests/run/tsets2
|
||||
/tests/run/tsidee2
|
||||
/tests/run/tsidee3
|
||||
/tests/run/tsimmeth
|
||||
/tests/run/tsimplesort
|
||||
/tests/run/tslices
|
||||
/tests/run/tsortdev
|
||||
/tests/run/tsplit
|
||||
/tests/run/tstempl
|
||||
/tests/run/tstmtexprs
|
||||
/tests/run/tstrange
|
||||
/tests/run/tstringinterp
|
||||
/tests/run/tstrlits
|
||||
/tests/run/tstrutil
|
||||
/tests/run/tsubrange
|
||||
/tests/run/tsubrange2
|
||||
/tests/run/ttables
|
||||
/tests/run/ttables2
|
||||
/tests/run/ttoseq
|
||||
/tests/run/ttypedesc1
|
||||
/tests/run/tunhandledexc
|
||||
/tests/run/tunidecode
|
||||
/tests/run/tunittests
|
||||
/tests/run/tuserassert
|
||||
/tests/run/tvarargs_vs_generic
|
||||
/tests/run/tvardecl
|
||||
/tests/run/tvariantasgn
|
||||
/tests/run/tvariantstack
|
||||
/tests/run/tvarious1
|
||||
/tests/run/tvarnums
|
||||
/tests/run/tvarres1
|
||||
/tests/run/tvarres2
|
||||
/tests/run/tvartup
|
||||
/tests/run/tvtable
|
||||
/tests/run/twrongexc
|
||||
/tests/run/txmlgen
|
||||
/tests/run/txmltree
|
||||
/tests/run/tzeroarray
|
||||
/tests/system/helpers/readall_echo
|
||||
/tests/system/io
|
||||
/tests/system/params
|
||||
/tests/tester
|
||||
/tests/threads/tactors
|
||||
/tests/threads/tactors2
|
||||
/tests/threads/tthreadanalysis2
|
||||
/tests/threads/tthreadanalysis3
|
||||
/tests/threads/tthreadheapviolation1
|
||||
/tools/nimgrep
|
||||
|
||||
1
bin/empty.txt
Normal file
1
bin/empty.txt
Normal file
@@ -0,0 +1 @@
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
200
build.bat
200
build.bat
@@ -1,200 +0,0 @@
|
||||
@echo off
|
||||
REM Generated by niminst
|
||||
SET CC=gcc
|
||||
SET LINKER=gcc
|
||||
SET COMP_FLAGS=-w -O3 -fno-strict-aliasing
|
||||
SET LINK_FLAGS=
|
||||
|
||||
REM call the compiler:
|
||||
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimrod.c -o build\1_1\nimrod.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimrod.c -o build\1_1\nimrod.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\system.c -o build\1_1\system.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\system.c -o build\1_1\system.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\commands.c -o build\1_1\commands.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\commands.c -o build\1_1\commands.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\os.c -o build\1_1\os.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\os.c -o build\1_1\os.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\strutils.c -o build\1_1\strutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\strutils.c -o build\1_1\strutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseutils.c -o build\1_1\parseutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseutils.c -o build\1_1\parseutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\times.c -o build\1_1\times.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\times.c -o build\1_1\times.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\winlean.c -o build\1_1\winlean.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\winlean.c -o build\1_1\winlean.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\msgs.c -o build\1_1\msgs.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\msgs.c -o build\1_1\msgs.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\options.c -o build\1_1\options.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\options.c -o build\1_1\options.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lists.c -o build\1_1\lists.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lists.c -o build\1_1\lists.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\strtabs.c -o build\1_1\strtabs.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\strtabs.c -o build\1_1\strtabs.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\hashes.c -o build\1_1\hashes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\hashes.c -o build\1_1\hashes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\tables.c -o build\1_1\tables.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\tables.c -o build\1_1\tables.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\math.c -o build\1_1\math.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\math.c -o build\1_1\math.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sockets.c -o build\1_1\sockets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sockets.c -o build\1_1\sockets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ropes.c -o build\1_1\ropes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ropes.c -o build\1_1\ropes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\platform.c -o build\1_1\platform.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\platform.c -o build\1_1\platform.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\crc.c -o build\1_1\crc.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\crc.c -o build\1_1\crc.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nversion.c -o build\1_1\nversion.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nversion.c -o build\1_1\nversion.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\condsyms.c -o build\1_1\condsyms.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\condsyms.c -o build\1_1\condsyms.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ast.c -o build\1_1\ast.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ast.c -o build\1_1\ast.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\idents.c -o build\1_1\idents.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\idents.c -o build\1_1\idents.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\intsets.c -o build\1_1\intsets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\intsets.c -o build\1_1\intsets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\idgen.c -o build\1_1\idgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\idgen.c -o build\1_1\idgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\astalgo.c -o build\1_1\astalgo.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\astalgo.c -o build\1_1\astalgo.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodutils.c -o build\1_1\rodutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodutils.c -o build\1_1\rodutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\extccomp.c -o build\1_1\extccomp.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\extccomp.c -o build\1_1\extccomp.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\osproc.c -o build\1_1\osproc.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\osproc.c -o build\1_1\osproc.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\streams.c -o build\1_1\streams.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\streams.c -o build\1_1\streams.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\wordrecg.c -o build\1_1\wordrecg.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\wordrecg.c -o build\1_1\wordrecg.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\babelcmd.c -o build\1_1\babelcmd.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\babelcmd.c -o build\1_1\babelcmd.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexer.c -o build\1_1\lexer.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexer.c -o build\1_1\lexer.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimlexbase.c -o build\1_1\nimlexbase.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimlexbase.c -o build\1_1\nimlexbase.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\llstream.c -o build\1_1\llstream.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\llstream.c -o build\1_1\llstream.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimconf.c -o build\1_1\nimconf.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimconf.c -o build\1_1\nimconf.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\main.c -o build\1_1\main.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\main.c -o build\1_1\main.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\syntaxes.c -o build\1_1\syntaxes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\syntaxes.c -o build\1_1\syntaxes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parser.c -o build\1_1\parser.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parser.c -o build\1_1\parser.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\pbraces.c -o build\1_1\pbraces.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\pbraces.c -o build\1_1\pbraces.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\filters.c -o build\1_1\filters.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\filters.c -o build\1_1\filters.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\renderer.c -o build\1_1\renderer.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\renderer.c -o build\1_1\renderer.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\filter_tmpl.c -o build\1_1\filter_tmpl.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\filter_tmpl.c -o build\1_1\filter_tmpl.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodread.c -o build\1_1\rodread.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodread.c -o build\1_1\rodread.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\types.c -o build\1_1\types.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\types.c -o build\1_1\types.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\trees.c -o build\1_1\trees.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\trees.c -o build\1_1\trees.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\memfiles.c -o build\1_1\memfiles.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\memfiles.c -o build\1_1\memfiles.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodwrite.c -o build\1_1\rodwrite.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodwrite.c -o build\1_1\rodwrite.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\passes.c -o build\1_1\passes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\passes.c -o build\1_1\passes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\magicsys.c -o build\1_1\magicsys.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\magicsys.c -o build\1_1\magicsys.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimsets.c -o build\1_1\nimsets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimsets.c -o build\1_1\nimsets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\bitsets.c -o build\1_1\bitsets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\bitsets.c -o build\1_1\bitsets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semthreads.c -o build\1_1\semthreads.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semthreads.c -o build\1_1\semthreads.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\importer.c -o build\1_1\importer.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\importer.c -o build\1_1\importer.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lookups.c -o build\1_1\lookups.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lookups.c -o build\1_1\lookups.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semdata.c -o build\1_1\semdata.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semdata.c -o build\1_1\semdata.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\treetab.c -o build\1_1\treetab.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\treetab.c -o build\1_1\treetab.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\evals.c -o build\1_1\evals.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\evals.c -o build\1_1\evals.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semfold.c -o build\1_1\semfold.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semfold.c -o build\1_1\semfold.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\saturate.c -o build\1_1\saturate.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\saturate.c -o build\1_1\saturate.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\transf.c -o build\1_1\transf.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\transf.c -o build\1_1\transf.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgmeth.c -o build\1_1\cgmeth.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgmeth.c -o build\1_1\cgmeth.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sempass2.c -o build\1_1\sempass2.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sempass2.c -o build\1_1\sempass2.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lambdalifting.c -o build\1_1\lambdalifting.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lambdalifting.c -o build\1_1\lambdalifting.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\evaltempl.c -o build\1_1\evaltempl.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\evaltempl.c -o build\1_1\evaltempl.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sem.c -o build\1_1\sem.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sem.c -o build\1_1\sem.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\procfind.c -o build\1_1\procfind.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\procfind.c -o build\1_1\procfind.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\pragmas.c -o build\1_1\pragmas.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\pragmas.c -o build\1_1\pragmas.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semtypinst.c -o build\1_1\semtypinst.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semtypinst.c -o build\1_1\semtypinst.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sigmatch.c -o build\1_1\sigmatch.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sigmatch.c -o build\1_1\sigmatch.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parampatterns.c -o build\1_1\parampatterns.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parampatterns.c -o build\1_1\parampatterns.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen.c -o build\1_1\docgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen.c -o build\1_1\docgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstast.c -o build\1_1\rstast.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstast.c -o build\1_1\rstast.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstgen.c -o build\1_1\rstgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstgen.c -o build\1_1\rstgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\algorithm.c -o build\1_1\algorithm.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\algorithm.c -o build\1_1\algorithm.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\patterns.c -o build\1_1\patterns.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\patterns.c -o build\1_1\patterns.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgen.c -o build\1_1\cgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgen.c -o build\1_1\cgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgutils.c -o build\1_1\ccgutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgutils.c -o build\1_1\ccgutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgendata.c -o build\1_1\cgendata.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgendata.c -o build\1_1\cgendata.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgmerge.c -o build\1_1\ccgmerge.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgmerge.c -o build\1_1\ccgmerge.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\jsgen.c -o build\1_1\jsgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\jsgen.c -o build\1_1\jsgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\json.c -o build\1_1\json.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\json.c -o build\1_1\json.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexbase.c -o build\1_1\lexbase.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexbase.c -o build\1_1\lexbase.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\unicode.c -o build\1_1\unicode.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\unicode.c -o build\1_1\unicode.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\passaux.c -o build\1_1\passaux.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\passaux.c -o build\1_1\passaux.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\depends.c -o build\1_1\depends.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\depends.c -o build\1_1\depends.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen2.c -o build\1_1\docgen2.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen2.c -o build\1_1\docgen2.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\service.c -o build\1_1\service.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\service.c -o build\1_1\service.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseopt.c -o build\1_1\parseopt.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseopt.c -o build\1_1\parseopt.o
|
||||
|
||||
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_1\nimrod.o build\1_1\system.o build\1_1\commands.o build\1_1\os.o build\1_1\strutils.o build\1_1\parseutils.o build\1_1\times.o build\1_1\winlean.o build\1_1\msgs.o build\1_1\options.o build\1_1\lists.o build\1_1\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.o build\1_1\sockets.o build\1_1\ropes.o build\1_1\platform.o build\1_1\crc.o build\1_1\nversion.o build\1_1\condsyms.o build\1_1\ast.o build\1_1\idents.o build\1_1\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\babelcmd.o build\1_1\lexer.o build\1_1\nimlexbase.o build\1_1\llstream.o build\1_1\nimconf.o build\1_1\main.o build\1_1\syntaxes.o build\1_1\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\types.o build\1_1\trees.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\saturate.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sempass2.o build\1_1\lambdalifting.o build\1_1\evaltempl.o build\1_1\sem.o build\1_1\procfind.o build\1_1\pragmas.o build\1_1\semtypinst.o build\1_1\sigmatch.o build\1_1\parampatterns.o build\1_1\docgen.o build\1_1\rstast.o build\1_1\rst.o build\1_1\rstgen.o build\1_1\highlite.o build\1_1\algorithm.o build\1_1\aliases.o build\1_1\patterns.o build\1_1\cgen.o build\1_1\ccgutils.o build\1_1\cgendata.o build\1_1\ccgmerge.o build\1_1\jsgen.o build\1_1\json.o build\1_1\lexbase.o build\1_1\unicode.o build\1_1\passaux.o build\1_1\depends.o build\1_1\docgen2.o build\1_1\service.o build\1_1\parseopt.o
|
||||
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_1\nimrod.o build\1_1\system.o build\1_1\commands.o build\1_1\os.o build\1_1\strutils.o build\1_1\parseutils.o build\1_1\times.o build\1_1\winlean.o build\1_1\msgs.o build\1_1\options.o build\1_1\lists.o build\1_1\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.o build\1_1\sockets.o build\1_1\ropes.o build\1_1\platform.o build\1_1\crc.o build\1_1\nversion.o build\1_1\condsyms.o build\1_1\ast.o build\1_1\idents.o build\1_1\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\babelcmd.o build\1_1\lexer.o build\1_1\nimlexbase.o build\1_1\llstream.o build\1_1\nimconf.o build\1_1\main.o build\1_1\syntaxes.o build\1_1\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\types.o build\1_1\trees.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\saturate.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sempass2.o build\1_1\lambdalifting.o build\1_1\evaltempl.o build\1_1\sem.o build\1_1\procfind.o build\1_1\pragmas.o build\1_1\semtypinst.o build\1_1\sigmatch.o build\1_1\parampatterns.o build\1_1\docgen.o build\1_1\rstast.o build\1_1\rst.o build\1_1\rstgen.o build\1_1\highlite.o build\1_1\algorithm.o build\1_1\aliases.o build\1_1\patterns.o build\1_1\cgen.o build\1_1\ccgutils.o build\1_1\cgendata.o build\1_1\ccgmerge.o build\1_1\jsgen.o build\1_1\json.o build\1_1\lexbase.o build\1_1\unicode.o build\1_1\passaux.o build\1_1\depends.o build\1_1\docgen2.o build\1_1\service.o build\1_1\parseopt.o
|
||||
|
||||
|
||||
ECHO SUCCESS
|
||||
|
||||
1
build/empty.txt
Normal file
1
build/empty.txt
Normal file
@@ -0,0 +1 @@
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
200
build64.bat
200
build64.bat
@@ -1,200 +0,0 @@
|
||||
@echo off
|
||||
REM Generated by niminst
|
||||
SET CC=gcc
|
||||
SET LINKER=gcc
|
||||
SET COMP_FLAGS=-w -O3 -fno-strict-aliasing
|
||||
SET LINK_FLAGS=
|
||||
|
||||
REM call the compiler:
|
||||
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimrod.c -o build\1_2\nimrod.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimrod.c -o build\1_2\nimrod.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\system.c -o build\1_2\system.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\system.c -o build\1_2\system.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\commands.c -o build\1_2\commands.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\commands.c -o build\1_2\commands.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\os.c -o build\1_2\os.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\os.c -o build\1_2\os.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\strutils.c -o build\1_2\strutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\strutils.c -o build\1_2\strutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseutils.c -o build\1_2\parseutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseutils.c -o build\1_2\parseutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\times.c -o build\1_2\times.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\times.c -o build\1_2\times.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\winlean.c -o build\1_2\winlean.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\winlean.c -o build\1_2\winlean.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\msgs.c -o build\1_2\msgs.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\msgs.c -o build\1_2\msgs.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\options.c -o build\1_2\options.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\options.c -o build\1_2\options.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lists.c -o build\1_2\lists.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lists.c -o build\1_2\lists.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\strtabs.c -o build\1_2\strtabs.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\strtabs.c -o build\1_2\strtabs.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\hashes.c -o build\1_2\hashes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\hashes.c -o build\1_2\hashes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\tables.c -o build\1_2\tables.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\tables.c -o build\1_2\tables.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\math.c -o build\1_2\math.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\math.c -o build\1_2\math.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sockets.c -o build\1_2\sockets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sockets.c -o build\1_2\sockets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ropes.c -o build\1_2\ropes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ropes.c -o build\1_2\ropes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\platform.c -o build\1_2\platform.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\platform.c -o build\1_2\platform.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\crc.c -o build\1_2\crc.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\crc.c -o build\1_2\crc.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nversion.c -o build\1_2\nversion.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nversion.c -o build\1_2\nversion.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\condsyms.c -o build\1_2\condsyms.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\condsyms.c -o build\1_2\condsyms.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ast.c -o build\1_2\ast.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ast.c -o build\1_2\ast.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\idents.c -o build\1_2\idents.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\idents.c -o build\1_2\idents.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\intsets.c -o build\1_2\intsets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\intsets.c -o build\1_2\intsets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\idgen.c -o build\1_2\idgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\idgen.c -o build\1_2\idgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\astalgo.c -o build\1_2\astalgo.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\astalgo.c -o build\1_2\astalgo.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodutils.c -o build\1_2\rodutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodutils.c -o build\1_2\rodutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\extccomp.c -o build\1_2\extccomp.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\extccomp.c -o build\1_2\extccomp.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\osproc.c -o build\1_2\osproc.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\osproc.c -o build\1_2\osproc.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\streams.c -o build\1_2\streams.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\streams.c -o build\1_2\streams.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\wordrecg.c -o build\1_2\wordrecg.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\wordrecg.c -o build\1_2\wordrecg.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\babelcmd.c -o build\1_2\babelcmd.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\babelcmd.c -o build\1_2\babelcmd.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexer.c -o build\1_2\lexer.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexer.c -o build\1_2\lexer.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimlexbase.c -o build\1_2\nimlexbase.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimlexbase.c -o build\1_2\nimlexbase.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\llstream.c -o build\1_2\llstream.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\llstream.c -o build\1_2\llstream.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimconf.c -o build\1_2\nimconf.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimconf.c -o build\1_2\nimconf.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\main.c -o build\1_2\main.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\main.c -o build\1_2\main.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\syntaxes.c -o build\1_2\syntaxes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\syntaxes.c -o build\1_2\syntaxes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parser.c -o build\1_2\parser.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parser.c -o build\1_2\parser.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\pbraces.c -o build\1_2\pbraces.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\pbraces.c -o build\1_2\pbraces.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\filters.c -o build\1_2\filters.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\filters.c -o build\1_2\filters.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\renderer.c -o build\1_2\renderer.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\renderer.c -o build\1_2\renderer.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\filter_tmpl.c -o build\1_2\filter_tmpl.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\filter_tmpl.c -o build\1_2\filter_tmpl.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodread.c -o build\1_2\rodread.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodread.c -o build\1_2\rodread.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\types.c -o build\1_2\types.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\types.c -o build\1_2\types.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\trees.c -o build\1_2\trees.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\trees.c -o build\1_2\trees.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\memfiles.c -o build\1_2\memfiles.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\memfiles.c -o build\1_2\memfiles.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodwrite.c -o build\1_2\rodwrite.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodwrite.c -o build\1_2\rodwrite.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\passes.c -o build\1_2\passes.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\passes.c -o build\1_2\passes.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\magicsys.c -o build\1_2\magicsys.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\magicsys.c -o build\1_2\magicsys.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimsets.c -o build\1_2\nimsets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimsets.c -o build\1_2\nimsets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\bitsets.c -o build\1_2\bitsets.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\bitsets.c -o build\1_2\bitsets.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semthreads.c -o build\1_2\semthreads.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semthreads.c -o build\1_2\semthreads.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\importer.c -o build\1_2\importer.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\importer.c -o build\1_2\importer.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lookups.c -o build\1_2\lookups.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lookups.c -o build\1_2\lookups.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semdata.c -o build\1_2\semdata.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semdata.c -o build\1_2\semdata.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\treetab.c -o build\1_2\treetab.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\treetab.c -o build\1_2\treetab.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\evals.c -o build\1_2\evals.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\evals.c -o build\1_2\evals.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semfold.c -o build\1_2\semfold.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semfold.c -o build\1_2\semfold.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\saturate.c -o build\1_2\saturate.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\saturate.c -o build\1_2\saturate.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\transf.c -o build\1_2\transf.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\transf.c -o build\1_2\transf.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgmeth.c -o build\1_2\cgmeth.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgmeth.c -o build\1_2\cgmeth.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sempass2.c -o build\1_2\sempass2.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sempass2.c -o build\1_2\sempass2.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lambdalifting.c -o build\1_2\lambdalifting.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lambdalifting.c -o build\1_2\lambdalifting.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\evaltempl.c -o build\1_2\evaltempl.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\evaltempl.c -o build\1_2\evaltempl.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sem.c -o build\1_2\sem.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sem.c -o build\1_2\sem.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\procfind.c -o build\1_2\procfind.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\procfind.c -o build\1_2\procfind.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\pragmas.c -o build\1_2\pragmas.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\pragmas.c -o build\1_2\pragmas.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semtypinst.c -o build\1_2\semtypinst.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semtypinst.c -o build\1_2\semtypinst.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sigmatch.c -o build\1_2\sigmatch.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sigmatch.c -o build\1_2\sigmatch.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parampatterns.c -o build\1_2\parampatterns.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parampatterns.c -o build\1_2\parampatterns.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstast.c -o build\1_2\rstast.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstast.c -o build\1_2\rstast.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstgen.c -o build\1_2\rstgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstgen.c -o build\1_2\rstgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\algorithm.c -o build\1_2\algorithm.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\algorithm.c -o build\1_2\algorithm.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\patterns.c -o build\1_2\patterns.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\patterns.c -o build\1_2\patterns.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgen.c -o build\1_2\cgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgen.c -o build\1_2\cgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgutils.c -o build\1_2\ccgutils.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgutils.c -o build\1_2\ccgutils.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgendata.c -o build\1_2\cgendata.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgendata.c -o build\1_2\cgendata.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgmerge.c -o build\1_2\ccgmerge.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgmerge.c -o build\1_2\ccgmerge.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\jsgen.c -o build\1_2\jsgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\jsgen.c -o build\1_2\jsgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\json.c -o build\1_2\json.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\json.c -o build\1_2\json.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexbase.c -o build\1_2\lexbase.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexbase.c -o build\1_2\lexbase.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\unicode.c -o build\1_2\unicode.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\unicode.c -o build\1_2\unicode.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\passaux.c -o build\1_2\passaux.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\passaux.c -o build\1_2\passaux.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\depends.c -o build\1_2\depends.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\depends.c -o build\1_2\depends.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen2.c -o build\1_2\docgen2.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen2.c -o build\1_2\docgen2.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\service.c -o build\1_2\service.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\service.c -o build\1_2\service.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o
|
||||
|
||||
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nimrod.o build\1_2\system.o build\1_2\commands.o build\1_2\os.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\times.o build\1_2\winlean.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\sockets.o build\1_2\ropes.o build\1_2\platform.o build\1_2\crc.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\babelcmd.o build\1_2\lexer.o build\1_2\nimlexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\types.o build\1_2\trees.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\saturate.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sempass2.o build\1_2\lambdalifting.o build\1_2\evaltempl.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\parampatterns.o build\1_2\docgen.o build\1_2\rstast.o build\1_2\rst.o build\1_2\rstgen.o build\1_2\highlite.o build\1_2\algorithm.o build\1_2\aliases.o build\1_2\patterns.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\jsgen.o build\1_2\json.o build\1_2\lexbase.o build\1_2\unicode.o build\1_2\passaux.o build\1_2\depends.o build\1_2\docgen2.o build\1_2\service.o build\1_2\parseopt.o
|
||||
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nimrod.o build\1_2\system.o build\1_2\commands.o build\1_2\os.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\times.o build\1_2\winlean.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\sockets.o build\1_2\ropes.o build\1_2\platform.o build\1_2\crc.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\babelcmd.o build\1_2\lexer.o build\1_2\nimlexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\types.o build\1_2\trees.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\saturate.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sempass2.o build\1_2\lambdalifting.o build\1_2\evaltempl.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\parampatterns.o build\1_2\docgen.o build\1_2\rstast.o build\1_2\rst.o build\1_2\rstgen.o build\1_2\highlite.o build\1_2\algorithm.o build\1_2\aliases.o build\1_2\patterns.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\jsgen.o build\1_2\json.o build\1_2\lexbase.o build\1_2\unicode.o build\1_2\passaux.o build\1_2\depends.o build\1_2\docgen2.o build\1_2\service.o build\1_2\parseopt.o
|
||||
|
||||
|
||||
ECHO SUCCESS
|
||||
|
||||
@@ -42,7 +42,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
|
||||
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
|
||||
result = arNo
|
||||
if a == nil or b == nil: return
|
||||
if ContainsOrIncl(marker, a.id): return
|
||||
if containsOrIncl(marker, a.id): return
|
||||
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
|
||||
case a.kind
|
||||
of tyObject:
|
||||
@@ -54,11 +54,11 @@ proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
result = isPartOfAux(a.sons[i], b, marker)
|
||||
if result == arYes: return
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc isPartOf(a, b: PType): TAnalysisResult =
|
||||
## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
|
||||
var marker = InitIntSet()
|
||||
var marker = initIntSet()
|
||||
# watch out: parameters reversed because I'm too lazy to change the code...
|
||||
result = isPartOfAux(b, a, marker)
|
||||
|
||||
@@ -115,7 +115,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
|
||||
var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
|
||||
|
||||
if SameValue(x, y): result = arYes
|
||||
if sameValue(x, y): result = arYes
|
||||
else: result = arNo
|
||||
# else: maybe and no are accurate
|
||||
else:
|
||||
@@ -140,7 +140,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
result = isPartOf(a[1], b[1])
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isPartOf(a[0], b[0])
|
||||
else: nil
|
||||
else: discard
|
||||
# Calls return a new location, so a default of ``arNo`` is fine.
|
||||
else:
|
||||
# go down recursively; this is quite demanding:
|
||||
@@ -177,6 +177,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a[0], b)
|
||||
if result == arNo: result = arMaybe
|
||||
else: nil
|
||||
else: nil
|
||||
else: discard
|
||||
else: discard
|
||||
|
||||
|
||||
402
compiler/ast.nim
402
compiler/ast.nim
@@ -13,7 +13,7 @@ import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
intsets, idgen
|
||||
|
||||
type
|
||||
type
|
||||
TCallingConvention* = enum
|
||||
ccDefault, # proc has no explicit calling convention
|
||||
ccStdCall, # procedure is stdcall
|
||||
@@ -62,7 +62,7 @@ type
|
||||
nkTripleStrLit, # a triple string literal """
|
||||
nkNilLit, # the nil literal
|
||||
# end of atoms
|
||||
nkMetaNode, # difficult to explain; represents itself
|
||||
nkMetaNode_Obsolete, # difficult to explain; represents itself
|
||||
# (used for macros)
|
||||
nkDotCall, # used to temporarily flag a nkCall node;
|
||||
# this is used
|
||||
@@ -131,7 +131,7 @@ type
|
||||
nkFormalParams, # formal parameters
|
||||
nkOfInherit, # inherited from symbol
|
||||
|
||||
nkModule, # the syntax tree of a module
|
||||
nkImportAs, # a 'as' b in an import statement
|
||||
nkProcDef, # a proc
|
||||
nkMethodDef, # a method
|
||||
nkConverterDef, # a converter
|
||||
@@ -178,6 +178,7 @@ type
|
||||
nkIncludeStmt, # an include statement
|
||||
nkBindStmt, # a bind statement
|
||||
nkMixinStmt, # a mixin statement
|
||||
nkUsingStmt, # an using statement
|
||||
nkCommentStmt, # a comment statement
|
||||
nkStmtListExpr, # a statement list followed by an expr; this is used
|
||||
# to allow powerful multi-line templates
|
||||
@@ -187,9 +188,15 @@ type
|
||||
nkStmtListType, # a statement list ending in a type; for macros
|
||||
nkBlockType, # a statement block ending in a type; for macros
|
||||
# types as syntactic trees:
|
||||
|
||||
nkWith, # distinct with `foo`
|
||||
nkWithout, # distinct without `foo`
|
||||
|
||||
nkTypeOfExpr, # type(1+2)
|
||||
nkObjectTy, # object body
|
||||
nkTupleTy, # tuple body
|
||||
nkTypeClassTy, # user-defined type class
|
||||
nkStaticTy, # ``static[T]``
|
||||
nkRecList, # list of object parts
|
||||
nkRecCase, # case section of object
|
||||
nkRecWhen, # when section of object
|
||||
@@ -211,11 +218,11 @@ type
|
||||
nkClosure, # (prc, env)-pair (internally used for code gen)
|
||||
nkGotoState, # used for the state machine (for iterators)
|
||||
nkState, # give a label to a code section (for iterators)
|
||||
nkBreakState # special break statement for easier code generation
|
||||
nkBreakState, # special break statement for easier code generation
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # already 30 flags!
|
||||
TSymFlag* = enum # already 32 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
|
||||
@@ -229,13 +236,14 @@ type
|
||||
sfVolatile, # variable is volatile
|
||||
sfRegister, # variable should be placed in a register
|
||||
sfPure, # object is "pure" that means it has no type-information
|
||||
|
||||
# enum is "pure", its values need qualified access
|
||||
# variable is "pure"; it's an explicit "global"
|
||||
sfNoSideEffect, # proc has no side effects
|
||||
sfSideEffect, # proc may have side effects; cannot prove it has none
|
||||
sfMainModule, # module is the main module
|
||||
sfSystemModule, # module is the system module
|
||||
sfNoReturn, # proc never returns (an exit proc)
|
||||
sfAddrTaken, # the variable's address is taken (ex- or implicitely);
|
||||
sfAddrTaken, # the variable's address is taken (ex- or implicitly);
|
||||
# *OR*: a proc is indirectly called (used as first class)
|
||||
sfCompilerProc, # proc is a compiler proc, that is a C proc that is
|
||||
# needed for the code generator
|
||||
@@ -254,7 +262,7 @@ type
|
||||
# for interfacing with C++, JS
|
||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||
# language; for interfacing with Objective C
|
||||
sfDiscardable, # returned value may be discarded implicitely
|
||||
sfDiscardable, # returned value may be discarded implicitly
|
||||
sfDestructor, # proc is destructor
|
||||
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
||||
|
||||
@@ -278,11 +286,12 @@ const
|
||||
# the compiler will avoid printing such names
|
||||
# in user messages.
|
||||
|
||||
sfHoist* = sfVolatile ## proc return value can be hoisted
|
||||
|
||||
sfNoForward* = sfRegister
|
||||
# forward declarations are not required (per module)
|
||||
|
||||
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
||||
# require RC ops
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
nkWhen* = nkWhenStmt
|
||||
@@ -290,7 +299,7 @@ const
|
||||
nkEffectList* = nkArgList
|
||||
# hacks ahead: an nkEffectList is a node with 4 children:
|
||||
exceptionEffects* = 0 # exceptions at position 0
|
||||
readEffects* = 1 # read effects at position 1
|
||||
usesEffects* = 1 # read effects at position 1
|
||||
writeEffects* = 2 # write effects at position 2
|
||||
tagEffects* = 3 # user defined tag ('gc', 'time' etc.)
|
||||
effectListLen* = 4 # list of effects list
|
||||
@@ -331,13 +340,70 @@ type
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyIter, # unused
|
||||
tyProxy # used as errornous type (for idetools)
|
||||
tyTypeClass,
|
||||
|
||||
tyBuiltInTypeClass #\
|
||||
# Type such as the catch-all object, tuple, seq, etc
|
||||
|
||||
tyUserTypeClass #\
|
||||
# the body of a user-defined type class
|
||||
|
||||
tyUserTypeClassInst #\
|
||||
# Instance of a parametric user-defined type class.
|
||||
# Structured similarly to tyGenericInst.
|
||||
# tyGenericInst represents concrete types, while
|
||||
# this is still a "generic param" that will bind types
|
||||
# and resolves them during sigmatch and instantiation.
|
||||
|
||||
tyCompositeTypeClass #\
|
||||
# Type such as seq[Number]
|
||||
# The notes for tyUserTypeClassInst apply here as well
|
||||
# sons[0]: the original expression used by the user.
|
||||
# sons[1]: fully expanded and instantiated meta type
|
||||
# (potentially following aliases)
|
||||
|
||||
tyAnd, tyOr, tyNot #\
|
||||
# boolean type classes such as `string|int`,`not seq`,
|
||||
# `Sortable and Enumable`, etc
|
||||
|
||||
tyAnything #\
|
||||
# a type class matching any type
|
||||
|
||||
tyStatic #\
|
||||
# a value known at compile type (the underlying type is .base)
|
||||
|
||||
tyFromExpr #\
|
||||
# This is a type representing an expression that depends
|
||||
# on generic parameters (the exprsesion is stored in t.n)
|
||||
# It will be converted to a real type only during generic
|
||||
# instantiation and prior to this it has the potential to
|
||||
# be any type.
|
||||
|
||||
tyFieldAccessor #\
|
||||
# Expressions such as Type.field (valid in contexts such
|
||||
# as the `is` operator and magics like `high` and `low`).
|
||||
# Could be lifted to a single argument proc returning the
|
||||
# field value.
|
||||
# sons[0]: type of containing object or tuple
|
||||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
static:
|
||||
# remind us when TTypeKind stops to fit in a single 64-bit word
|
||||
assert TTypeKind.high.ord <= 63
|
||||
|
||||
const
|
||||
tyPureObject* = tyTuple
|
||||
GcTypeKinds* = {tyRef, tySequence, tyString}
|
||||
tyError* = tyProxy # as an errornous node should match everything
|
||||
|
||||
tyUnknownTypes* = {tyError, tyFromExpr}
|
||||
|
||||
tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
|
||||
tyUserTypeClass, tyUserTypeClassInst,
|
||||
tyAnd, tyOr, tyNot, tyAnything}
|
||||
|
||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
|
||||
|
||||
type
|
||||
TTypeKinds* = set[TTypeKind]
|
||||
|
||||
@@ -351,9 +417,14 @@ type
|
||||
# efficiency
|
||||
nfTransf, # node has been transformed
|
||||
nfSem # node has been checked for semantics
|
||||
|
||||
nfDotField # the call can use a dot operator
|
||||
nfDotSetter # the call can use a setter dot operarator
|
||||
nfExplicitCall # x.y() was used instead of x.y
|
||||
nfExprCall # this is an attempt to call a regular expression
|
||||
nfIsRef # this node is a 'ref' node; used for the VM
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 19)
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
tfFinal, # is the object final?
|
||||
@@ -361,26 +432,40 @@ type
|
||||
tfAcyclic, # type is acyclic (for GC optimization)
|
||||
tfEnumHasHoles, # enum cannot be mapped into a range
|
||||
tfShallow, # type can be shallow copied on assignment
|
||||
tfThread, # proc type is marked as ``thread``
|
||||
tfThread, # proc type is marked as ``thread``; alias for ``gcsafe``
|
||||
tfFromGeneric, # type is an instantiation of a generic; this is needed
|
||||
# because for instantiations of objects, structural
|
||||
# type equality has to be used
|
||||
tfInstantiated, # XXX: used to mark generic params after instantiation.
|
||||
# if the concrete type happens to be an implicit generic
|
||||
# this can lead to invalid proc signatures in the second
|
||||
# pass of semProcTypeNode performed after instantiation.
|
||||
# this won't be needed if we don't perform this redundant
|
||||
# second pass (stay tuned).
|
||||
tfUnresolved, # marks unresolved typedesc/static params: e.g.
|
||||
# proc foo(T: typedesc, list: seq[T]): var T
|
||||
# proc foo(L: static[int]): array[L, int]
|
||||
# can be attached to ranges to indicate that the range
|
||||
# depends on unresolved static params.
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
# used as return types for return type inference)
|
||||
tfAll, # type class requires all constraints to be met (default)
|
||||
tfAny, # type class requires any constraint to be met
|
||||
tfCapturesEnv, # whether proc really captures some environment
|
||||
tfByCopy, # pass object/tuple by copy (C backend)
|
||||
tfByRef, # pass object/tuple by reference (C backend)
|
||||
tfIterator, # type is really an iterator, not a tyProc
|
||||
tfShared, # type is 'shared'
|
||||
tfNotNil # type cannot be 'nil'
|
||||
tfNotNil, # type cannot be 'nil'
|
||||
|
||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||
# other type so that it requires inititalization
|
||||
tfHasShared, # type constains a "shared" constraint modifier somewhere
|
||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||
# or other type classes
|
||||
tfHasGCedMem, # type contains GC'ed memory
|
||||
tfPacked
|
||||
tfHasStatic
|
||||
tfGenericTypeParam
|
||||
tfImplicitTypeParam
|
||||
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
|
||||
# T and I here can bind to both typedesc and static types
|
||||
# before this is determined, we'll consider them to be a
|
||||
# wildcard type.
|
||||
tfGuarded # guarded pointer
|
||||
tfBorrowDot # distinct type borrows '.'
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
@@ -402,7 +487,8 @@ type
|
||||
skResult, # special 'result' variable
|
||||
skProc, # a proc
|
||||
skMethod, # a method
|
||||
skIterator, # an iterator
|
||||
skIterator, # an inline iterator
|
||||
skClosureIterator, # a resumable closure iterator
|
||||
skConverter, # a type converter
|
||||
skMacro, # a macro
|
||||
skTemplate, # a template; currently also misused for user-defined
|
||||
@@ -414,12 +500,16 @@ type
|
||||
skStub, # symbol is a stub and not yet loaded from the ROD
|
||||
# file (it is loaded on demand, which may
|
||||
# mean: never)
|
||||
skPackage # symbol is a package (used for canonicalization)
|
||||
TSymKinds* = set[TSymKind]
|
||||
|
||||
const
|
||||
routineKinds* = {skProc, skMethod, skIterator, skConverter,
|
||||
skMacro, skTemplate}
|
||||
routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||
skConverter, skMacro, skTemplate}
|
||||
tfIncompleteStruct* = tfVarargs
|
||||
tfUncheckedArray* = tfVarargs
|
||||
tfUnion* = tfNoSideEffect
|
||||
tfGcSafe* = tfThread
|
||||
skError* = skUnknown
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
@@ -470,7 +560,7 @@ type
|
||||
mFloat, mFloat32, mFloat64, mFloat128,
|
||||
mBool, mChar, mString, mCstring,
|
||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
||||
mVoidType, mPNimrodNode,
|
||||
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn,
|
||||
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||
mNaN, mInf, mNegInf,
|
||||
@@ -481,7 +571,7 @@ type
|
||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
||||
mNBindSym, mLocals, mNCallSite,
|
||||
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo
|
||||
mInstantiationInfo, mGetTypeInfo, mNGenSym
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
@@ -524,23 +614,25 @@ type
|
||||
PType* = ref TType
|
||||
PSym* = ref TSym
|
||||
TNode*{.final, acyclic.} = object # on a 32bit machine, this takes 32 bytes
|
||||
when defined(useNodeIds):
|
||||
id*: int
|
||||
typ*: PType
|
||||
comment*: string
|
||||
info*: TLineInfo
|
||||
flags*: TNodeFlags
|
||||
case Kind*: TNodeKind
|
||||
case kind*: TNodeKind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
intVal*: biggestInt
|
||||
intVal*: BiggestInt
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
floatVal*: biggestFloat
|
||||
floatVal*: BiggestFloat
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
strVal*: string
|
||||
of nkSym:
|
||||
sym*: PSym
|
||||
of nkIdent:
|
||||
ident*: PIdent
|
||||
else:
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
comment*: string
|
||||
|
||||
TSymSeq* = seq[PSym]
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
@@ -611,6 +703,7 @@ type
|
||||
TScope* = object
|
||||
depthLevel*: int
|
||||
symbols*: TStrTable
|
||||
usingSyms*: seq[PNode]
|
||||
parent*: PScope
|
||||
|
||||
PScope* = ref TScope
|
||||
@@ -619,8 +712,9 @@ type
|
||||
TSym* {.acyclic.} = object of TIdObj
|
||||
# proc and type instantiations are cached in the generic symbol
|
||||
case kind*: TSymKind
|
||||
of skType:
|
||||
of skType, skGenericParam:
|
||||
typeInstCache*: seq[PType]
|
||||
typScope*: PScope
|
||||
of routineKinds:
|
||||
procInstCache*: seq[PInstantiation]
|
||||
scope*: PScope # the scope where the proc was defined
|
||||
@@ -629,6 +723,11 @@ type
|
||||
# this is because in incremental compilation, when a module is about to
|
||||
# be replaced with a newer version, we must decrement the usage count
|
||||
# of all previously used generics.
|
||||
# For 'import as' we copy the module symbol but shallowCopy the 'tab'
|
||||
# and set the 'usedGenerics' to ... XXX gah! Better set module.name
|
||||
# instead? But this doesn't work either. --> We need an skModuleAlias?
|
||||
# No need, just leave it as skModule but set the owner accordingly and
|
||||
# check for the owner when touching 'usedGenerics'.
|
||||
usedGenerics*: seq[PInstantiation]
|
||||
tab*: TStrTable # interface table for modules
|
||||
else: nil
|
||||
@@ -657,12 +756,15 @@ type
|
||||
# (or not in symbol table)
|
||||
# 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
|
||||
# reference to another object to safe space)
|
||||
constraint*: PNode # additional constraints like 'lit|result'
|
||||
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||
# misused for the codegenDecl pragma in the hope
|
||||
# it won't cause problems
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
@@ -678,6 +780,9 @@ type
|
||||
# for record types a nkRecord node
|
||||
# for enum types a list of symbols
|
||||
# for tyInt it can be the int literal
|
||||
# for procs and tyGenericBody, it's the
|
||||
# the body of the user-defined type class
|
||||
# formal param list
|
||||
# else: unused
|
||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||
# mean that there is no destructor.
|
||||
@@ -732,19 +837,24 @@ type
|
||||
counter*: int
|
||||
data*: TObjectSeq
|
||||
|
||||
TImplication* = enum
|
||||
impUnknown, impNo, impYes
|
||||
|
||||
# BUGFIX: a module is overloadable so that a proc can have the
|
||||
# same name as an imported module. This is necessary because of
|
||||
# the poor naming choices in the standard library.
|
||||
|
||||
const
|
||||
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter,
|
||||
skModule, skTemplate, skMacro}
|
||||
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||
skConverter, skModule, skTemplate, skMacro}
|
||||
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
|
||||
tyGenericParam}
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
|
||||
tyVarargs}
|
||||
|
||||
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
|
||||
# var x = expr
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
@@ -758,22 +868,26 @@ const
|
||||
tyTuple, tySequence}
|
||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
||||
tyProc, tyString, tyError}
|
||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
|
||||
skIterator, skClosureIterator,
|
||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||
nfDotSetter, nfDotField,
|
||||
nfAllConst,nfIsRef}
|
||||
namePos* = 0
|
||||
patternPos* = 1 # empty except for term rewriting macros
|
||||
genericParamsPos* = 2
|
||||
paramsPos* = 3
|
||||
pragmasPos* = 4
|
||||
exceptionPos* = 5 # will be used for exception tracking
|
||||
optimizedCodePos* = 5 # will be used for exception tracking
|
||||
bodyPos* = 6 # position of body; use rodread.getBody() instead!
|
||||
resultPos* = 7
|
||||
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5!
|
||||
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
|
||||
|
||||
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCommand, nkCallStrLit, nkHiddenCallConv}
|
||||
|
||||
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
||||
nkLambdaKinds* = {nkLambda, nkDo}
|
||||
declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||
procDefs* = nkLambdaKinds + declarativeDefs
|
||||
@@ -782,12 +896,19 @@ const
|
||||
nkStrKinds* = {nkStrLit..nkTripleStrLit}
|
||||
|
||||
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
|
||||
skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skClosureIterator,
|
||||
skMethod, skConverter}
|
||||
|
||||
skIterators* = {skIterator, skClosureIterator}
|
||||
|
||||
lfFullExternalName* = lfParamCopy # \
|
||||
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
|
||||
# imported via 'importc: "fullname"' and no format string.
|
||||
|
||||
# creator procs:
|
||||
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym
|
||||
proc NewType*(kind: TTypeKind, owner: PSym): PType
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType
|
||||
proc newNode*(kind: TNodeKind): PNode
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
|
||||
@@ -858,6 +979,13 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||
var emptyNode* = newNode(nkEmpty)
|
||||
# There is a single empty node that is shared! Do not overwrite it!
|
||||
|
||||
var anyGlobal* = newSym(skVar, getIdent("*"), nil, unknownLineInfo())
|
||||
|
||||
proc isMetaType*(t: PType): bool =
|
||||
return t.kind in tyMetaTypes or
|
||||
(t.kind == tyStatic and t.n == nil) or
|
||||
tfHasMeta in t.flags
|
||||
|
||||
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
|
||||
t.sym = s
|
||||
s.typ = t
|
||||
@@ -874,7 +1002,7 @@ template fileIdx*(c: PSym): int32 =
|
||||
|
||||
template filename*(c: PSym): string =
|
||||
# XXX: this should be used only on module symbols
|
||||
c.position.int32.toFileName
|
||||
c.position.int32.toFilename
|
||||
|
||||
proc appendToModule*(m: PSym, n: PNode) =
|
||||
## The compiler will use this internally to add nodes that will be
|
||||
@@ -893,7 +1021,7 @@ const # for all kind of hash tables:
|
||||
proc copyStrTable(dest: var TStrTable, src: TStrTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
setlen(dest.data, len(src.data))
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyIdTable(dest: var TIdTable, src: TIdTable) =
|
||||
@@ -905,18 +1033,25 @@ proc copyIdTable(dest: var TIdTable, src: TIdTable) =
|
||||
proc copyTable(dest: var TTable, src: TTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
setlen(dest.data, len(src.data))
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyObjectSet(dest: var TObjectSet, src: TObjectSet) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
setlen(dest.data, len(src.data))
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc discardSons(father: PNode) =
|
||||
father.sons = nil
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = 482228 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
@@ -924,6 +1059,12 @@ proc newNode(kind: TNodeKind): PNode =
|
||||
result.info.fileIndex = int32(- 1)
|
||||
result.info.col = int16(- 1)
|
||||
result.info.line = int16(- 1)
|
||||
when defined(useNodeIds):
|
||||
result.id = gNodeId
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "KIND ", result.kind
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newIntNode(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
@@ -941,6 +1082,10 @@ proc newStrNode(kind: TNodeKind, strVal: string): PNode =
|
||||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
return n
|
||||
|
||||
proc newIdentNode(ident: PIdent, info: TLineInfo): PNode =
|
||||
result = newNode(nkIdent)
|
||||
result.ident = ident
|
||||
@@ -962,6 +1107,12 @@ proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
result.info = info
|
||||
when defined(useNodeIds):
|
||||
result.id = gNodeId
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "KIND ", result.kind
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
|
||||
new(result)
|
||||
@@ -969,6 +1120,12 @@ proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
|
||||
result.info = info
|
||||
if children > 0:
|
||||
newSeq(result.sons, children)
|
||||
when defined(useNodeIds):
|
||||
result.id = gNodeId
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "KIND ", result.kind
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
|
||||
typ: PType = nil): PNode =
|
||||
@@ -978,16 +1135,18 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
|
||||
result.typ = typ
|
||||
# XXX use shallowCopy here for ownership transfer:
|
||||
result.sons = sons
|
||||
when defined(useNodeIds):
|
||||
result.id = gNodeId
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "KIND ", result.kind
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
result.typ = typ
|
||||
|
||||
proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode =
|
||||
result = newNodeIT(nkMetaNode, info, typ)
|
||||
result.add(tree)
|
||||
|
||||
var emptyParams = newNode(nkFormalParams)
|
||||
emptyParams.addSon(emptyNode)
|
||||
|
||||
@@ -1000,15 +1159,15 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||
pragmas, exceptions, body]
|
||||
|
||||
|
||||
proc NewType(kind: TTypeKind, owner: PSym): PType =
|
||||
proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
result.owner = owner
|
||||
result.size = - 1
|
||||
result.align = 2 # default alignment
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
RegisterId(result)
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000 then
|
||||
# MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
|
||||
@@ -1040,24 +1199,23 @@ proc assignType(dest, src: PType) =
|
||||
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
|
||||
|
||||
proc copyType(t: PType, owner: PSym, keepId: bool): PType =
|
||||
result = newType(t.Kind, owner)
|
||||
result = newType(t.kind, owner)
|
||||
assignType(result, t)
|
||||
if keepId:
|
||||
result.id = t.id
|
||||
else:
|
||||
result.id = getID()
|
||||
when debugIds: RegisterId(result)
|
||||
when debugIds: registerId(result)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc copySym(s: PSym, keepId: bool = false): PSym =
|
||||
result = newSym(s.kind, s.name, s.owner, s.info)
|
||||
result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
if keepId:
|
||||
result.id = s.id
|
||||
else:
|
||||
result.id = getID()
|
||||
when debugIds: RegisterId(result)
|
||||
when debugIds: registerId(result)
|
||||
result.flags = s.flags
|
||||
result.magic = s.magic
|
||||
if s.kind == skModule:
|
||||
@@ -1066,13 +1224,27 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
|
||||
result.position = s.position
|
||||
result.loc = s.loc
|
||||
result.annex = s.annex # BUGFIX
|
||||
|
||||
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
||||
result = newSym(s.kind, newIdent, s.owner, info)
|
||||
# keep ID!
|
||||
result.ast = s.ast
|
||||
result.id = s.id
|
||||
result.flags = s.flags
|
||||
system.shallowCopy(result.tab, s.tab)
|
||||
result.options = s.options
|
||||
result.position = s.position
|
||||
result.loc = s.loc
|
||||
result.annex = s.annex
|
||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||
assert s.usedGenerics == nil
|
||||
|
||||
proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
|
||||
proc newSym(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
new(result)
|
||||
result.Name = Name
|
||||
result.Kind = symKind
|
||||
result.name = name
|
||||
result.kind = symKind
|
||||
result.flags = {}
|
||||
result.info = info
|
||||
result.options = gOptions
|
||||
@@ -1080,36 +1252,36 @@ proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
|
||||
result.offset = - 1
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
RegisterId(result)
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
|
||||
proc initStrTable(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newStrTable*: TStrTable =
|
||||
initStrTable(result)
|
||||
|
||||
proc initTable(x: var TTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdTable(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initObjectSet(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdNodeTable(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initNodeTable(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc sonsLen(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
@@ -1123,7 +1295,7 @@ proc newSons(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setlen(father.sons, length)
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
@@ -1133,16 +1305,43 @@ proc newSons(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setlen(father.sons, length)
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc addSon*(father, son: PType) {.deprecated.} =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
#assert((father.kind != tyGenericInvokation) or (son.kind != tyGenericInst))
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
result = t
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
proc isGCedMem*(t: PType): bool {.inline.} =
|
||||
result = t.kind in {tyString, tyRef, tySequence} or
|
||||
t.kind == tyProc and t.callConv == ccClosure
|
||||
|
||||
proc propagateToOwner*(owner, elem: PType) =
|
||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
||||
owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta})
|
||||
if tfNotNil in elem.flags:
|
||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}:
|
||||
owner.flags.incl tfNotNil
|
||||
elif owner.kind notin HaveTheirOwnEmpty:
|
||||
owner.flags.incl tfNeedsInit
|
||||
|
||||
if tfNeedsInit in elem.flags:
|
||||
if owner.kind in HaveTheirOwnEmpty: discard
|
||||
else: owner.flags.incl tfNeedsInit
|
||||
|
||||
if tfShared in elem.flags:
|
||||
owner.flags.incl tfHasShared
|
||||
|
||||
if elem.isMetaType:
|
||||
owner.flags.incl tfHasMeta
|
||||
|
||||
if owner.kind != tyProc:
|
||||
if elem.isGCedMem or tfHasGCedMem in elem.flags:
|
||||
owner.flags.incl tfHasGCedMem
|
||||
|
||||
proc rawAddSon*(father, son: PType) =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
if not son.isNil: propagateToOwner(father, son)
|
||||
|
||||
proc addSon(father, son: PNode) =
|
||||
assert son != nil
|
||||
@@ -1157,7 +1356,7 @@ proc delSon(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
var length = sonsLen(father)
|
||||
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
|
||||
setlen(father.sons, length - 1)
|
||||
setLen(father.sons, length - 1)
|
||||
|
||||
proc copyNode(src: PNode): PNode =
|
||||
# does not copy its sons!
|
||||
@@ -1167,13 +1366,16 @@ proc copyNode(src: PNode): PNode =
|
||||
result.info = src.info
|
||||
result.typ = src.typ
|
||||
result.flags = src.flags * PersistentNodeFlags
|
||||
case src.Kind
|
||||
when defined(useNodeIds):
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "COMES FROM ", src.id
|
||||
case src.kind
|
||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
||||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
# does not copy its sons, but provides space for them:
|
||||
@@ -1182,7 +1384,10 @@ proc shallowCopy*(src: PNode): PNode =
|
||||
result.info = src.info
|
||||
result.typ = src.typ
|
||||
result.flags = src.flags * PersistentNodeFlags
|
||||
case src.Kind
|
||||
when defined(useNodeIds):
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "COMES FROM ", src.id
|
||||
case src.kind
|
||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
||||
of nkSym: result.sym = src.sym
|
||||
@@ -1198,7 +1403,10 @@ proc copyTree(src: PNode): PNode =
|
||||
result.info = src.info
|
||||
result.typ = src.typ
|
||||
result.flags = src.flags * PersistentNodeFlags
|
||||
case src.Kind
|
||||
when defined(useNodeIds):
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "COMES FROM ", src.id
|
||||
case src.kind
|
||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
||||
of nkSym: result.sym = src.sym
|
||||
@@ -1256,14 +1464,14 @@ proc sonsNotNil(n: PNode): bool =
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc getInt*(a: PNode): biggestInt =
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
case a.kind
|
||||
of nkIntLit..nkUInt64Lit: result = a.intVal
|
||||
else:
|
||||
internalError(a.info, "getInt")
|
||||
result = 0
|
||||
|
||||
proc getFloat*(a: PNode): biggestFloat =
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal
|
||||
else:
|
||||
@@ -1287,13 +1495,25 @@ proc getStrOrChar*(a: PNode): string =
|
||||
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
case s.kind
|
||||
of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter:
|
||||
result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty
|
||||
else: nil
|
||||
of skProcKinds:
|
||||
result = sfFromGeneric in s.flags or
|
||||
(s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
|
||||
else: discard
|
||||
|
||||
proc skipGenericOwner*(s: PSym): PSym =
|
||||
internalAssert s.kind in skProcKinds
|
||||
## Generic instantiations are owned by their originating generic
|
||||
## symbol. This proc skips such owners and goes straigh to the owner
|
||||
## of the generic itself (the module or the enclosing proc).
|
||||
result = if sfFromGeneric in s.flags: s.owner.owner
|
||||
else: s.owner
|
||||
|
||||
proc originatingModule*(s: PSym): PSym =
|
||||
result = s.owner
|
||||
while result.kind != skModule: result = result.owner
|
||||
|
||||
proc isRoutine*(s: PSym): bool {.inline.} =
|
||||
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
|
||||
skConverter}
|
||||
result = s.kind in skProcKinds
|
||||
|
||||
proc hasPattern*(s: PSym): bool {.inline.} =
|
||||
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
|
||||
@@ -1301,9 +1521,13 @@ proc hasPattern*(s: PSym): bool {.inline.} =
|
||||
iterator items*(n: PNode): PNode =
|
||||
for i in 0.. <n.len: yield n.sons[i]
|
||||
|
||||
iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
|
||||
for i in 0.. <n.len: yield (i, n.sons[i])
|
||||
|
||||
proc isAtom*(n: PNode): bool {.inline.} =
|
||||
result = n.kind >= nkNone and n.kind <= nkNilLit
|
||||
|
||||
proc isEmptyType*(t: PType): bool {.inline.} =
|
||||
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
||||
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
||||
|
||||
|
||||
@@ -24,35 +24,35 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
|
||||
proc lineInfoToStr*(info: TLineInfo): PRope
|
||||
|
||||
# ----------------------- node sets: ---------------------------------------
|
||||
proc ObjectSetContains*(t: TObjectSet, obj: PObject): bool
|
||||
proc objectSetContains*(t: TObjectSet, obj: PObject): bool
|
||||
# returns true whether n is in t
|
||||
proc ObjectSetIncl*(t: var TObjectSet, obj: PObject)
|
||||
proc objectSetIncl*(t: var TObjectSet, obj: PObject)
|
||||
# include an element n in the table t
|
||||
proc ObjectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
|
||||
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
|
||||
# more are not needed ...
|
||||
|
||||
# ----------------------- (key, val)-Hashtables ----------------------------
|
||||
proc TablePut*(t: var TTable, key, val: PObject)
|
||||
proc TableGet*(t: TTable, key: PObject): PObject
|
||||
proc tablePut*(t: var TTable, key, val: PObject)
|
||||
proc tableGet*(t: TTable, key: PObject): PObject
|
||||
type
|
||||
TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found
|
||||
|
||||
proc TableSearch*(t: TTable, key, closure: PObject,
|
||||
proc tableSearch*(t: TTable, key, closure: PObject,
|
||||
comparator: TCmpProc): PObject
|
||||
# return val as soon as comparator returns true; if this never happens,
|
||||
# nil is returned
|
||||
|
||||
# ----------------------- str table -----------------------------------------
|
||||
proc StrTableContains*(t: TStrTable, n: PSym): bool
|
||||
proc StrTableAdd*(t: var TStrTable, n: PSym)
|
||||
proc StrTableGet*(t: TStrTable, name: PIdent): PSym
|
||||
proc strTableContains*(t: TStrTable, n: PSym): bool
|
||||
proc strTableAdd*(t: var TStrTable, n: PSym)
|
||||
proc strTableGet*(t: TStrTable, name: PIdent): PSym
|
||||
|
||||
type
|
||||
TTabIter*{.final.} = object # consider all fields here private
|
||||
h*: THash # current hash
|
||||
|
||||
proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||
proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||
|
||||
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||
# usage:
|
||||
# var
|
||||
# i: TTabIter
|
||||
@@ -69,8 +69,8 @@ type
|
||||
name*: PIdent
|
||||
|
||||
|
||||
proc InitIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
|
||||
proc NextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
|
||||
proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
|
||||
proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
|
||||
|
||||
# these are for debugging only: They are not really deprecated, but I want
|
||||
# the warning so that release versions do not contain debugging statements:
|
||||
@@ -79,15 +79,14 @@ proc debug*(n: PType) {.deprecated.}
|
||||
proc debug*(n: PNode) {.deprecated.}
|
||||
|
||||
# --------------------------- ident tables ----------------------------------
|
||||
proc IdTableGet*(t: TIdTable, key: PIdObj): PObject
|
||||
proc IdTableGet*(t: TIdTable, key: int): PObject
|
||||
proc IdTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
|
||||
proc IdTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
|
||||
proc idTableGet*(t: TIdTable, key: PIdObj): PObject
|
||||
proc idTableGet*(t: TIdTable, key: int): PObject
|
||||
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
|
||||
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
|
||||
# checks if `t` contains the `key` (compared by the pointer value, not only
|
||||
# `key`'s id)
|
||||
proc IdNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
|
||||
proc IdNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
|
||||
proc writeIdNodeTable*(t: TIdNodeTable)
|
||||
proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
|
||||
proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -111,9 +110,9 @@ type
|
||||
data*: TIIPairSeq
|
||||
|
||||
|
||||
proc initIITable*(x: var TIITable)
|
||||
proc IITableGet*(t: TIITable, key: int): int
|
||||
proc IITablePut*(t: var TIITable, key, val: int)
|
||||
proc initIiTable*(x: var TIITable)
|
||||
proc iiTableGet*(t: TIITable, key: int): int
|
||||
proc iiTablePut*(t: var TIITable, key, val: int)
|
||||
|
||||
# implementation
|
||||
|
||||
@@ -129,7 +128,7 @@ proc skipConvTakeType*(n: PNode): PNode =
|
||||
result = n.skipConv
|
||||
result.typ = n.typ
|
||||
|
||||
proc SameValue*(a, b: PNode): bool =
|
||||
proc sameValue*(a, b: PNode): bool =
|
||||
result = false
|
||||
case a.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
@@ -141,7 +140,7 @@ proc SameValue*(a, b: PNode): bool =
|
||||
else:
|
||||
# don't raise an internal error for 'nimrod check':
|
||||
#InternalError(a.info, "SameValue")
|
||||
nil
|
||||
discard
|
||||
|
||||
proc leValue*(a, b: PNode): bool =
|
||||
# a <= b?
|
||||
@@ -156,7 +155,13 @@ proc leValue*(a, b: PNode): bool =
|
||||
else:
|
||||
# don't raise an internal error for 'nimrod check':
|
||||
#InternalError(a.info, "leValue")
|
||||
nil
|
||||
discard
|
||||
|
||||
proc weakLeValue*(a, b: PNode): TImplication =
|
||||
if a.kind notin nkLiterals or b.kind notin nkLiterals:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = if leValue(a, b): impYes else: impNo
|
||||
|
||||
proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||
result = nil
|
||||
@@ -166,7 +171,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||
result = lookupInRecord(n.sons[i], field)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
if (n.sons[0].kind != nkSym): InternalError(n.info, "lookupInRecord")
|
||||
if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
|
||||
result = lookupInRecord(n.sons[0], field)
|
||||
if result != nil: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
@@ -182,14 +187,14 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||
proc getModule(s: PSym): PSym =
|
||||
result = s
|
||||
assert((result.kind == skModule) or (result.owner != result))
|
||||
while (result != nil) and (result.kind != skModule): result = result.owner
|
||||
while result != nil and result.kind != skModule: result = result.owner
|
||||
|
||||
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||
for i in countup(start, sonsLen(list) - 1):
|
||||
if list.sons[i].kind == nkSym:
|
||||
result = list.sons[i].sym
|
||||
if result.name.id == ident.id: return
|
||||
else: InternalError(list.info, "getSymFromList")
|
||||
else: internalError(list.info, "getSymFromList")
|
||||
result = nil
|
||||
|
||||
proc hashNode(p: PObject): THash =
|
||||
@@ -203,7 +208,7 @@ proc spaces(x: int): PRope =
|
||||
# returns x spaces
|
||||
result = toRope(repeatChar(x))
|
||||
|
||||
proc toYamlChar(c: Char): string =
|
||||
proc toYamlChar(c: char): string =
|
||||
case c
|
||||
of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
|
||||
of '\'', '\"', '\\': result = '\\' & c
|
||||
@@ -216,7 +221,7 @@ proc makeYamlString*(s: string): PRope =
|
||||
const MaxLineLength = 64
|
||||
result = nil
|
||||
var res = "\""
|
||||
for i in countup(0, len(s) - 1):
|
||||
for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
|
||||
if (i + 1) mod MaxLineLength == 0:
|
||||
add(res, '\"')
|
||||
add(res, "\n")
|
||||
@@ -262,7 +267,7 @@ proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
|
||||
app(result, "]")
|
||||
assert(mycount == n.counter)
|
||||
|
||||
proc ropeConstr(indent: int, c: openarray[PRope]): PRope =
|
||||
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
||||
# array of (name, value) pairs
|
||||
var istr = spaces(indent + 2)
|
||||
result = toRope("{")
|
||||
@@ -277,7 +282,7 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
elif ContainsOrIncl(marker, n.id):
|
||||
elif containsOrIncl(marker, n.id):
|
||||
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
|
||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
||||
else:
|
||||
@@ -298,7 +303,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
elif ContainsOrIncl(marker, n.id):
|
||||
elif containsOrIncl(marker, n.id):
|
||||
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
|
||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
||||
else:
|
||||
@@ -315,7 +320,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
||||
makeYamlString($n.kind),
|
||||
toRope("sym"), symToYamlAux(n.sym, marker,
|
||||
indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker,
|
||||
indent + 2, maxRecDepth - 1), toRope("flags"), FlagsToStr(n.flags),
|
||||
indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags),
|
||||
toRope("callconv"),
|
||||
makeYamlString(CallingConvToStr[n.callConv]),
|
||||
toRope("size"), toRope(n.size),
|
||||
@@ -336,9 +341,12 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
|
||||
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
|
||||
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
||||
appf(result, ",$N$1\"floatVal\": $2",
|
||||
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
|
||||
[istr, toRope(n.floatVal.toStrMaxPrecision)])
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
|
||||
if n.strVal.isNil:
|
||||
appf(result, ",$N$1\"strVal\": null", [istr])
|
||||
else:
|
||||
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
|
||||
of nkSym:
|
||||
appf(result, ",$N$1\"sym\": $2",
|
||||
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
|
||||
@@ -360,15 +368,15 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
|
||||
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker = InitIntSet()
|
||||
var marker = initIntSet()
|
||||
result = treeToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker = InitIntSet()
|
||||
var marker = initIntSet()
|
||||
result = typeToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker = InitIntSet()
|
||||
var marker = initIntSet()
|
||||
result = symToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope
|
||||
@@ -406,9 +414,12 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
||||
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
|
||||
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
||||
appf(result, ",$N$1\"floatVal\": $2",
|
||||
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
|
||||
[istr, toRope(n.floatVal.toStrMaxPrecision)])
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
|
||||
if n.strVal.isNil:
|
||||
appf(result, ",$N$1\"strVal\": null", [istr])
|
||||
else:
|
||||
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
|
||||
of nkSym:
|
||||
appf(result, ",$N$1\"sym\": $2_$3",
|
||||
[istr, toRope(n.sym.name.s), toRope(n.sym.id)])
|
||||
@@ -430,11 +441,16 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
|
||||
proc debug(n: PSym) =
|
||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
||||
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
|
||||
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
|
||||
flagsToStr(n.loc.flags)])))
|
||||
proc debug(n: PSym) =
|
||||
if n == nil:
|
||||
writeln(stdout, "null")
|
||||
elif n.kind == skUnknown:
|
||||
writeln(stdout, "skUnknown")
|
||||
else:
|
||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
||||
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [
|
||||
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
|
||||
flagsToStr(n.loc.flags), lineInfoToStr(n.info)])))
|
||||
|
||||
proc debug(n: PType) =
|
||||
writeln(stdout, ropeToStr(debugType(n)))
|
||||
@@ -451,18 +467,18 @@ proc nextTry(h, maxHash: THash): THash =
|
||||
# generates each int in range(maxHash) exactly once (see any text on
|
||||
# random-number generation for proof).
|
||||
|
||||
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
|
||||
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
|
||||
# returns true whether n is in t
|
||||
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
|
||||
while t.data[h] != nil:
|
||||
if (t.data[h] == obj):
|
||||
while t.data[h] != nil:
|
||||
if t.data[h] == obj:
|
||||
return true
|
||||
h = nextTry(h, high(t.data))
|
||||
result = false
|
||||
|
||||
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
|
||||
var h: THash = HashNode(obj) and high(data)
|
||||
while data[h] != nil:
|
||||
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
|
||||
var h: THash = hashNode(obj) and high(data)
|
||||
while data[h] != nil:
|
||||
assert(data[h] != obj)
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
@@ -470,8 +486,8 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
|
||||
|
||||
proc objectSetEnlarge(t: var TObjectSet) =
|
||||
var n: TObjectSeq
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
newSeq(n, len(t.data) * GrowthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
|
||||
swap(t.data, n)
|
||||
|
||||
@@ -482,7 +498,7 @@ proc objectSetIncl(t: var TObjectSet, obj: PObject) =
|
||||
|
||||
proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
|
||||
# returns true if obj is already in the string table:
|
||||
var h: THash = HashNode(obj) and high(t.data)
|
||||
var h: THash = hashNode(obj) and high(t.data)
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
if it == nil: break
|
||||
@@ -498,7 +514,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
|
||||
inc(t.counter)
|
||||
result = false
|
||||
|
||||
proc TableRawGet(t: TTable, key: PObject): int =
|
||||
proc tableRawGet(t: TTable, key: PObject): int =
|
||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key == key:
|
||||
@@ -506,7 +522,7 @@ proc TableRawGet(t: TTable, key: PObject): int =
|
||||
h = nextTry(h, high(t.data))
|
||||
result = -1
|
||||
|
||||
proc TableSearch(t: TTable, key, closure: PObject,
|
||||
proc tableSearch(t: TTable, key, closure: PObject,
|
||||
comparator: TCmpProc): PObject =
|
||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
@@ -517,13 +533,13 @@ proc TableSearch(t: TTable, key, closure: PObject,
|
||||
h = nextTry(h, high(t.data))
|
||||
result = nil
|
||||
|
||||
proc TableGet(t: TTable, key: PObject): PObject =
|
||||
var index = TableRawGet(t, key)
|
||||
proc tableGet(t: TTable, key: PObject): PObject =
|
||||
var index = tableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
proc TableRawInsert(data: var TPairSeq, key, val: PObject) =
|
||||
var h: THash = HashNode(key) and high(data)
|
||||
proc tableRawInsert(data: var TPairSeq, key, val: PObject) =
|
||||
var h: THash = hashNode(key) and high(data)
|
||||
while data[h].key != nil:
|
||||
assert(data[h].key != key)
|
||||
h = nextTry(h, high(data))
|
||||
@@ -531,23 +547,23 @@ proc TableRawInsert(data: var TPairSeq, key, val: PObject) =
|
||||
data[h].key = key
|
||||
data[h].val = val
|
||||
|
||||
proc TableEnlarge(t: var TTable) =
|
||||
proc tableEnlarge(t: var TTable) =
|
||||
var n: TPairSeq
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
newSeq(n, len(t.data) * GrowthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
if t.data[i].key != nil: TableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
swap(t.data, n)
|
||||
|
||||
proc TablePut(t: var TTable, key, val: PObject) =
|
||||
var index = TableRawGet(t, key)
|
||||
proc tablePut(t: var TTable, key, val: PObject) =
|
||||
var index = tableRawGet(t, key)
|
||||
if index >= 0:
|
||||
t.data[index].val = val
|
||||
else:
|
||||
if mustRehash(len(t.data), t.counter): TableEnlarge(t)
|
||||
TableRawInsert(t.data, key, val)
|
||||
if mustRehash(len(t.data), t.counter): tableEnlarge(t)
|
||||
tableRawInsert(t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
proc StrTableContains(t: TStrTable, n: PSym): bool =
|
||||
proc strTableContains(t: TStrTable, n: PSym): bool =
|
||||
var h: THash = n.name.h and high(t.data) # start with real hash value
|
||||
while t.data[h] != nil:
|
||||
if (t.data[h] == n):
|
||||
@@ -555,18 +571,35 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
|
||||
h = nextTry(h, high(t.data))
|
||||
result = false
|
||||
|
||||
proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
|
||||
proc strTableRawInsert(data: var TSymSeq, n: PSym) =
|
||||
var h: THash = n.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
if data[h] == n:
|
||||
# allowed for 'export' feature:
|
||||
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
return
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
data[h] = n
|
||||
if sfImmediate notin n.flags:
|
||||
# fast path:
|
||||
while data[h] != nil:
|
||||
if data[h] == n:
|
||||
# allowed for 'export' feature:
|
||||
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
return
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
data[h] = n
|
||||
else:
|
||||
# slow path; we have to ensure immediate symbols are preferred for
|
||||
# symbol lookups.
|
||||
# consider the chain: foo (immediate), foo, bar, bar (immediate)
|
||||
# then bar (immediate) gets replaced with foo (immediate) and the non
|
||||
# immediate foo is picked! Thus we need to replace it with the first
|
||||
# slot that has in fact the same identifier stored in it!
|
||||
var favPos = -1
|
||||
while data[h] != nil:
|
||||
if data[h] == n: return
|
||||
if favPos < 0 and data[h].name.id == n.name.id: favPos = h
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
data[h] = n
|
||||
if favPos >= 0: swap data[h], data[favPos]
|
||||
|
||||
proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
|
||||
proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
|
||||
assert prevSym.name.h == newSym.name.h
|
||||
var h: THash = prevSym.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
@@ -576,22 +609,22 @@ proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
|
||||
h = nextTry(h, high(data))
|
||||
assert false
|
||||
|
||||
proc SymTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
|
||||
SymTabReplaceRaw(t.data, prevSym, newSym)
|
||||
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
|
||||
symTabReplaceRaw(t.data, prevSym, newSym)
|
||||
|
||||
proc StrTableEnlarge(t: var TStrTable) =
|
||||
proc strTableEnlarge(t: var TStrTable) =
|
||||
var n: TSymSeq
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
newSeq(n, len(t.data) * GrowthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
if t.data[i] != nil: StrTableRawInsert(n, t.data[i])
|
||||
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
|
||||
swap(t.data, n)
|
||||
|
||||
proc StrTableAdd(t: var TStrTable, n: PSym) =
|
||||
if mustRehash(len(t.data), t.counter): StrTableEnlarge(t)
|
||||
StrTableRawInsert(t.data, n)
|
||||
proc strTableAdd(t: var TStrTable, n: PSym) =
|
||||
if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
|
||||
strTableRawInsert(t.data, n)
|
||||
inc(t.counter)
|
||||
|
||||
proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||
# returns true if n is already in the string table:
|
||||
# It is essential that `n` is written nevertheless!
|
||||
# This way the newest redefinition is picked by the semantic analyses!
|
||||
@@ -605,15 +638,15 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||
return true # found it
|
||||
h = nextTry(h, high(t.data))
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
StrTableEnlarge(t)
|
||||
StrTableRawInsert(t.data, n)
|
||||
strTableEnlarge(t)
|
||||
strTableRawInsert(t.data, n)
|
||||
else:
|
||||
assert(t.data[h] == nil)
|
||||
t.data[h] = n
|
||||
inc(t.counter)
|
||||
result = false
|
||||
|
||||
proc StrTableGet(t: TStrTable, name: PIdent): PSym =
|
||||
proc strTableGet(t: TStrTable, name: PIdent): PSym =
|
||||
var h: THash = name.h and high(t.data)
|
||||
while true:
|
||||
result = t.data[h]
|
||||
@@ -621,19 +654,19 @@ proc StrTableGet(t: TStrTable, name: PIdent): PSym =
|
||||
if result.name.id == name.id: break
|
||||
h = nextTry(h, high(t.data))
|
||||
|
||||
proc InitIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
||||
proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
||||
ti.h = s.h
|
||||
ti.name = s
|
||||
if tab.Counter == 0: result = nil
|
||||
else: result = NextIdentIter(ti, tab)
|
||||
if tab.counter == 0: result = nil
|
||||
else: result = nextIdentIter(ti, tab)
|
||||
|
||||
proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||
var h, start: THash
|
||||
h = ti.h and high(tab.data)
|
||||
start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
if result.Name.id == ti.name.id: break
|
||||
if result.name.id == ti.name.id: break
|
||||
h = nextTry(h, high(tab.data))
|
||||
if h == start:
|
||||
result = nil
|
||||
@@ -641,13 +674,13 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||
result = tab.data[h]
|
||||
ti.h = nextTry(h, high(tab.data))
|
||||
|
||||
proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||
excluding: TIntSet): PSym =
|
||||
var h: THash = ti.h and high(tab.data)
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
if result.Name.id == ti.name.id and not Contains(excluding, result.id):
|
||||
if result.name.id == ti.name.id and not contains(excluding, result.id):
|
||||
break
|
||||
h = nextTry(h, high(tab.data))
|
||||
if h == start:
|
||||
@@ -655,35 +688,35 @@ proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||
break
|
||||
result = tab.data[h]
|
||||
ti.h = nextTry(h, high(tab.data))
|
||||
if result != nil and Contains(excluding, result.id): result = nil
|
||||
if result != nil and contains(excluding, result.id): result = nil
|
||||
|
||||
proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
|
||||
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
|
||||
excluding: TIntSet): PSym =
|
||||
ti.h = s.h
|
||||
ti.name = s
|
||||
if tab.Counter == 0: result = nil
|
||||
else: result = NextIdentExcluding(ti, tab, excluding)
|
||||
if tab.counter == 0: result = nil
|
||||
else: result = nextIdentExcluding(ti, tab, excluding)
|
||||
|
||||
proc InitTabIter(ti: var TTabIter, tab: TStrTable): PSym =
|
||||
proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
|
||||
ti.h = 0 # we start by zero ...
|
||||
if tab.counter == 0:
|
||||
result = nil # FIX 1: removed endless loop
|
||||
else:
|
||||
result = NextIter(ti, tab)
|
||||
result = nextIter(ti, tab)
|
||||
|
||||
proc NextIter(ti: var TTabIter, tab: TStrTable): PSym =
|
||||
proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
|
||||
result = nil
|
||||
while (ti.h <= high(tab.data)):
|
||||
result = tab.data[ti.h]
|
||||
Inc(ti.h) # ... and increment by one always
|
||||
inc(ti.h) # ... and increment by one always
|
||||
if result != nil: break
|
||||
|
||||
iterator items*(tab: TStrTable): PSym =
|
||||
var it: TTabIter
|
||||
var s = InitTabIter(it, tab)
|
||||
var s = initTabIter(it, tab)
|
||||
while s != nil:
|
||||
yield s
|
||||
s = NextIter(it, tab)
|
||||
s = nextIter(it, tab)
|
||||
|
||||
proc hasEmptySlot(data: TIdPairSeq): bool =
|
||||
for h in countup(0, high(data)):
|
||||
@@ -691,27 +724,27 @@ proc hasEmptySlot(data: TIdPairSeq): bool =
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc IdTableRawGet(t: TIdTable, key: int): int =
|
||||
proc idTableRawGet(t: TIdTable, key: int): int =
|
||||
var h: THash
|
||||
h = key and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if (t.data[h].key.id == key):
|
||||
if t.data[h].key.id == key:
|
||||
return h
|
||||
h = nextTry(h, high(t.data))
|
||||
result = - 1
|
||||
|
||||
proc IdTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
|
||||
var index = IdTableRawGet(t, key.id)
|
||||
proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
|
||||
var index = idTableRawGet(t, key.id)
|
||||
if index >= 0: result = t.data[index].key == key
|
||||
else: result = false
|
||||
|
||||
proc IdTableGet(t: TIdTable, key: PIdObj): PObject =
|
||||
var index = IdTableRawGet(t, key.id)
|
||||
proc idTableGet(t: TIdTable, key: PIdObj): PObject =
|
||||
var index = idTableRawGet(t, key.id)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
proc IdTableGet(t: TIdTable, key: int): PObject =
|
||||
var index = IdTableRawGet(t, key)
|
||||
proc idTableGet(t: TIdTable, key: int): PObject =
|
||||
var index = idTableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
@@ -720,7 +753,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
|
||||
if t.data[i].key != nil:
|
||||
yield (t.data[i].key.id, t.data[i].val)
|
||||
|
||||
proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
||||
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
||||
var h: THash
|
||||
h = key.id and high(data)
|
||||
while data[h].key != nil:
|
||||
@@ -730,33 +763,30 @@ proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
||||
data[h].key = key
|
||||
data[h].val = val
|
||||
|
||||
proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
|
||||
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
|
||||
var
|
||||
index: int
|
||||
n: TIdPairSeq
|
||||
index = IdTableRawGet(t, key.id)
|
||||
index = idTableRawGet(t, key.id)
|
||||
if index >= 0:
|
||||
assert(t.data[index].key != nil)
|
||||
t.data[index].val = val
|
||||
else:
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
newSeq(n, len(t.data) * GrowthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
if t.data[i].key != nil:
|
||||
IdTableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
idTableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
assert(hasEmptySlot(n))
|
||||
swap(t.data, n)
|
||||
IdTableRawInsert(t.data, key, val)
|
||||
idTableRawInsert(t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
iterator IdTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
|
||||
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
|
||||
for i in 0 .. high(t.data):
|
||||
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
|
||||
|
||||
proc writeIdNodeTable(t: TIdNodeTable) =
|
||||
nil
|
||||
|
||||
proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
|
||||
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
|
||||
var h: THash
|
||||
h = key.id and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
@@ -765,17 +795,17 @@ proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
|
||||
h = nextTry(h, high(t.data))
|
||||
result = - 1
|
||||
|
||||
proc IdNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
|
||||
proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
|
||||
var index: int
|
||||
index = IdNodeTableRawGet(t, key)
|
||||
index = idNodeTableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
proc IdNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
|
||||
proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
|
||||
if not isNil(t.data):
|
||||
result = IdNodeTableGet(t, key)
|
||||
result = idNodeTableGet(t, key)
|
||||
|
||||
proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
|
||||
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
|
||||
var h: THash
|
||||
h = key.id and high(data)
|
||||
while data[h].key != nil:
|
||||
@@ -785,25 +815,25 @@ proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
|
||||
data[h].key = key
|
||||
data[h].val = val
|
||||
|
||||
proc IdNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
|
||||
var index = IdNodeTableRawGet(t, key)
|
||||
proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
|
||||
var index = idNodeTableRawGet(t, key)
|
||||
if index >= 0:
|
||||
assert(t.data[index].key != nil)
|
||||
t.data[index].val = val
|
||||
else:
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
var n: TIdNodePairSeq
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
newSeq(n, len(t.data) * GrowthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
if t.data[i].key != nil:
|
||||
IdNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
swap(t.data, n)
|
||||
IdNodeTableRawInsert(t.data, key, val)
|
||||
idNodeTableRawInsert(t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
proc IdNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
|
||||
proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
|
||||
if isNil(t.data): initIdNodeTable(t)
|
||||
IdNodeTablePut(t, key, val)
|
||||
idNodeTablePut(t, key, val)
|
||||
|
||||
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
|
||||
for i in 0 .. high(t.data):
|
||||
@@ -811,24 +841,23 @@ iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
|
||||
|
||||
proc initIITable(x: var TIITable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, startSize)
|
||||
for i in countup(0, startSize - 1): x.data[i].key = InvalidKey
|
||||
newSeq(x.data, StartSize)
|
||||
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
|
||||
|
||||
proc IITableRawGet(t: TIITable, key: int): int =
|
||||
proc iiTableRawGet(t: TIITable, key: int): int =
|
||||
var h: THash
|
||||
h = key and high(t.data) # start with real hash value
|
||||
while t.data[h].key != InvalidKey:
|
||||
if (t.data[h].key == key):
|
||||
return h
|
||||
if t.data[h].key == key: return h
|
||||
h = nextTry(h, high(t.data))
|
||||
result = - 1
|
||||
result = -1
|
||||
|
||||
proc IITableGet(t: TIITable, key: int): int =
|
||||
var index = IITableRawGet(t, key)
|
||||
proc iiTableGet(t: TIITable, key: int): int =
|
||||
var index = iiTableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = InvalidKey
|
||||
|
||||
proc IITableRawInsert(data: var TIIPairSeq, key, val: int) =
|
||||
proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
|
||||
var h: THash
|
||||
h = key and high(data)
|
||||
while data[h].key != InvalidKey:
|
||||
@@ -838,19 +867,19 @@ proc IITableRawInsert(data: var TIIPairSeq, key, val: int) =
|
||||
data[h].key = key
|
||||
data[h].val = val
|
||||
|
||||
proc IITablePut(t: var TIITable, key, val: int) =
|
||||
var index = IITableRawGet(t, key)
|
||||
proc iiTablePut(t: var TIITable, key, val: int) =
|
||||
var index = iiTableRawGet(t, key)
|
||||
if index >= 0:
|
||||
assert(t.data[index].key != InvalidKey)
|
||||
t.data[index].val = val
|
||||
else:
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
var n: TIIPairSeq
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
newSeq(n, len(t.data) * GrowthFactor)
|
||||
for i in countup(0, high(n)): n[i].key = InvalidKey
|
||||
for i in countup(0, high(t.data)):
|
||||
if t.data[i].key != InvalidKey:
|
||||
IITableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
iiTableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
swap(t.data, n)
|
||||
IITableRawInsert(t.data, key, val)
|
||||
iiTableRawInsert(t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
@@ -13,7 +13,7 @@ import parseutils, strutils, strtabs, os, options, msgs, lists
|
||||
|
||||
proc addPath*(path: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, path):
|
||||
lists.PrependStr(options.searchPaths, path)
|
||||
lists.prependStr(options.searchPaths, path)
|
||||
|
||||
proc versionSplitPos(s: string): int =
|
||||
result = s.len-2
|
||||
@@ -45,9 +45,9 @@ proc `<.`(a, b: string): bool =
|
||||
|
||||
proc addPackage(packages: PStringTable, p: string) =
|
||||
let x = versionSplitPos(p)
|
||||
let name = p.subStr(0, x-1)
|
||||
let name = p.substr(0, x-1)
|
||||
if x < p.len:
|
||||
let version = p.subStr(x+1)
|
||||
let version = p.substr(x+1)
|
||||
if packages[name] <. version:
|
||||
packages[name] = version
|
||||
else:
|
||||
@@ -60,8 +60,8 @@ iterator chosen(packages: PStringTable): string =
|
||||
|
||||
proc addBabelPath(p: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, p):
|
||||
if gVerbosity >= 1: Message(info, hintPath, p)
|
||||
lists.PrependStr(options.lazyPaths, p)
|
||||
if gVerbosity >= 1: message(info, hintPath, p)
|
||||
lists.prependStr(options.lazyPaths, p)
|
||||
|
||||
proc addPathWithNimFiles(p: string, info: TLineInfo) =
|
||||
proc hasNimFile(dir: string): bool =
|
||||
|
||||
@@ -18,53 +18,53 @@ type
|
||||
const
|
||||
ElemSize* = sizeof(int8) * 8
|
||||
|
||||
proc BitSetInit*(b: var TBitSet, length: int)
|
||||
proc BitSetUnion*(x: var TBitSet, y: TBitSet)
|
||||
proc BitSetDiff*(x: var TBitSet, y: TBitSet)
|
||||
proc BitSetSymDiff*(x: var TBitSet, y: TBitSet)
|
||||
proc BitSetIntersect*(x: var TBitSet, y: TBitSet)
|
||||
proc BitSetIncl*(x: var TBitSet, elem: BiggestInt)
|
||||
proc BitSetExcl*(x: var TBitSet, elem: BiggestInt)
|
||||
proc BitSetIn*(x: TBitSet, e: BiggestInt): bool
|
||||
proc BitSetEquals*(x, y: TBitSet): bool
|
||||
proc BitSetContains*(x, y: TBitSet): bool
|
||||
proc bitSetInit*(b: var TBitSet, length: int)
|
||||
proc bitSetUnion*(x: var TBitSet, y: TBitSet)
|
||||
proc bitSetDiff*(x: var TBitSet, y: TBitSet)
|
||||
proc bitSetSymDiff*(x: var TBitSet, y: TBitSet)
|
||||
proc bitSetIntersect*(x: var TBitSet, y: TBitSet)
|
||||
proc bitSetIncl*(x: var TBitSet, elem: BiggestInt)
|
||||
proc bitSetExcl*(x: var TBitSet, elem: BiggestInt)
|
||||
proc bitSetIn*(x: TBitSet, e: BiggestInt): bool
|
||||
proc bitSetEquals*(x, y: TBitSet): bool
|
||||
proc bitSetContains*(x, y: TBitSet): bool
|
||||
# implementation
|
||||
|
||||
proc BitSetIn(x: TBitSet, e: BiggestInt): bool =
|
||||
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
|
||||
result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
|
||||
toU8(0)
|
||||
|
||||
proc BitSetIncl(x: var TBitSet, elem: BiggestInt) =
|
||||
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)))
|
||||
|
||||
proc BitSetExcl(x: var TBitSet, elem: BiggestInt) =
|
||||
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)))
|
||||
|
||||
proc BitSetInit(b: var TBitSet, length: int) =
|
||||
proc bitSetInit(b: var TBitSet, length: int) =
|
||||
newSeq(b, length)
|
||||
|
||||
proc BitSetUnion(x: var TBitSet, y: TBitSet) =
|
||||
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] or y[i]
|
||||
|
||||
proc BitSetDiff(x: var TBitSet, y: TBitSet) =
|
||||
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] and not y[i]
|
||||
|
||||
proc BitSetSymDiff(x: var TBitSet, y: TBitSet) =
|
||||
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] xor y[i]
|
||||
|
||||
proc BitSetIntersect(x: var TBitSet, y: TBitSet) =
|
||||
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] and y[i]
|
||||
|
||||
proc BitSetEquals(x, y: TBitSet): bool =
|
||||
proc bitSetEquals(x, y: TBitSet): bool =
|
||||
for i in countup(0, high(x)):
|
||||
if x[i] != y[i]:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc BitSetContains(x, y: TBitSet): bool =
|
||||
proc bitSetContains(x, y: TBitSet): bool =
|
||||
for i in countup(0, high(x)):
|
||||
if (x[i] and not y[i]) != int8(0):
|
||||
return false
|
||||
|
||||
@@ -19,6 +19,7 @@ c2nim - C to Nimrod source converter
|
||||
Usage: c2nim [options] inputfile [options]
|
||||
Options:
|
||||
-o, --out:FILE set output filename
|
||||
--cpp process C++ input file
|
||||
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
||||
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
||||
--cdecl annotate procs with ``{.cdecl.}``
|
||||
@@ -31,25 +32,38 @@ Options:
|
||||
--skipinclude do not convert ``#include`` to ``import``
|
||||
--typeprefixes generate ``T`` and ``P`` type prefixes
|
||||
--skipcomments do not copy comments
|
||||
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
|
||||
--keepBodies keep C++'s method bodies
|
||||
--spliceHeader parse and emit header before source file
|
||||
-v, --version write c2nim's version
|
||||
-h, --help show this help
|
||||
"""
|
||||
|
||||
proc main(infile, outfile: string, options: PParserOptions) =
|
||||
var start = getTime()
|
||||
var stream = LLStreamOpen(infile, fmRead)
|
||||
proc parse(infile: string, options: PParserOptions): PNode =
|
||||
var stream = llStreamOpen(infile, fmRead)
|
||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
||||
var p: TParser
|
||||
openParser(p, infile, stream, options)
|
||||
var module = parseUnit(p)
|
||||
result = parseUnit(p)
|
||||
closeParser(p)
|
||||
renderModule(module, outfile)
|
||||
|
||||
proc main(infile, outfile: string, options: PParserOptions, spliceHeader: bool) =
|
||||
var start = getTime()
|
||||
if spliceHeader and infile.splitFile.ext == ".c" and existsFile(infile.changeFileExt(".h")):
|
||||
var header_module = parse(infile.changeFileExt(".h"), options)
|
||||
var source_module = parse(infile, options)
|
||||
for n in source_module:
|
||||
addson(header_module, n)
|
||||
renderModule(header_module, outfile)
|
||||
else:
|
||||
renderModule(parse(infile, options), outfile)
|
||||
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start),
|
||||
formatSize(getTotalMem())])
|
||||
|
||||
var
|
||||
infile = ""
|
||||
outfile = ""
|
||||
spliceHeader = false
|
||||
parserOptions = newParserOptions()
|
||||
for kind, key, val in getopt():
|
||||
case kind
|
||||
@@ -63,6 +77,7 @@ for kind, key, val in getopt():
|
||||
stdout.write(Version & "\n")
|
||||
quit(0)
|
||||
of "o", "out": outfile = val
|
||||
of "spliceheader": spliceHeader = true
|
||||
else:
|
||||
if not parserOptions.setOption(key, val):
|
||||
stdout.writeln("[Error] unknown option: " & key)
|
||||
@@ -74,4 +89,4 @@ else:
|
||||
if outfile.len == 0:
|
||||
outfile = changeFileExt(infile, "nim")
|
||||
infile = addFileExt(infile, "h")
|
||||
main(infile, outfile, parserOptions)
|
||||
main(infile, outfile, parserOptions, spliceHeader)
|
||||
|
||||
@@ -82,6 +82,8 @@ type
|
||||
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
|
||||
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
|
||||
pxComma, pxSemiColon, pxColon,
|
||||
pxAngleRi # '>' but determined to be the end of a
|
||||
# template's angle bracket
|
||||
TTokKinds* = set[TTokKind]
|
||||
|
||||
type
|
||||
@@ -101,7 +103,7 @@ type
|
||||
inDirective: bool
|
||||
|
||||
proc getTok*(L: var TLexer, tok: var TToken)
|
||||
proc PrintTok*(tok: TToken)
|
||||
proc printTok*(tok: TToken)
|
||||
proc `$`*(tok: TToken): string
|
||||
# implementation
|
||||
|
||||
@@ -136,7 +138,7 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
|
||||
msgs.GlobalError(info, msg, arg)
|
||||
|
||||
proc TokKindToStr*(k: TTokKind): string =
|
||||
proc tokKindToStr*(k: TTokKind): string =
|
||||
case k
|
||||
of pxEof: result = "[EOF]"
|
||||
of pxInvalid: result = "[invalid]"
|
||||
@@ -202,15 +204,16 @@ proc TokKindToStr*(k: TTokKind): string =
|
||||
of pxColon: result = ":"
|
||||
of pxCurlyLe: result = "{"
|
||||
of pxCurlyRi: result = "}"
|
||||
of pxAngleRi: result = "> [end of template]"
|
||||
|
||||
proc `$`(tok: TToken): string =
|
||||
case tok.xkind
|
||||
of pxSymbol, pxInvalid, pxStarComment, pxLineComment, pxStrLit: result = tok.s
|
||||
of pxIntLit, pxInt64Lit: result = $tok.iNumber
|
||||
of pxFloatLit: result = $tok.fNumber
|
||||
else: result = TokKindToStr(tok.xkind)
|
||||
else: result = tokKindToStr(tok.xkind)
|
||||
|
||||
proc PrintTok(tok: TToken) =
|
||||
proc printTok(tok: TToken) =
|
||||
writeln(stdout, $tok)
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
@@ -220,12 +223,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.s, buf[pos])
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
add(tok.s, '_')
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
L.bufPos = pos
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
@@ -236,7 +239,7 @@ proc isFloatLiteral(s: string): bool =
|
||||
proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0b
|
||||
tok.base = base2
|
||||
var xi: biggestInt = 0
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -261,7 +264,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
proc getNumber8(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1 # skip 0
|
||||
tok.base = base8
|
||||
var xi: biggestInt = 0
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -286,7 +289,7 @@ proc getNumber8(L: var TLexer, tok: var TToken) =
|
||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0x
|
||||
tok.base = base16
|
||||
var xi: biggestInt = 0
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -312,19 +315,34 @@ proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getFloating(L: var TLexer, tok: var TToken) =
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if L.buf[L.bufpos] in {'e', 'E'}:
|
||||
add(tok.s, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
add(tok.s, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
|
||||
proc getNumber(L: var TLexer, tok: var TToken) =
|
||||
tok.base = base10
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||
add(tok.s, '.')
|
||||
if L.buf[L.bufpos] == '.':
|
||||
add(tok.s, "0.")
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
|
||||
getFloating(L, tok)
|
||||
else:
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if L.buf[L.bufpos] == '.':
|
||||
add(tok.s, '.')
|
||||
inc(L.bufpos)
|
||||
getFloating(L, tok)
|
||||
try:
|
||||
if isFloatLiteral(tok.s):
|
||||
tok.fnumber = parseFloat(tok.s)
|
||||
tok.xkind = pxFloatLit
|
||||
else:
|
||||
tok.iNumber = ParseInt(tok.s)
|
||||
tok.iNumber = parseInt(tok.s)
|
||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
||||
tok.xkind = pxInt64Lit
|
||||
else:
|
||||
@@ -336,10 +354,10 @@ proc getNumber(L: var TLexer, tok: var TToken) =
|
||||
# ignore type suffix:
|
||||
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)
|
||||
|
||||
proc HandleCRLF(L: var TLexer, pos: int): int =
|
||||
proc handleCRLF(L: var TLexer, pos: int): int =
|
||||
case L.buf[pos]
|
||||
of CR: result = nimlexbase.HandleCR(L, pos)
|
||||
of LF: result = nimlexbase.HandleLF(L, pos)
|
||||
of CR: result = nimlexbase.handleCR(L, pos)
|
||||
of LF: result = nimlexbase.handleLF(L, pos)
|
||||
else: result = pos
|
||||
|
||||
proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
|
||||
@@ -379,6 +397,23 @@ proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
|
||||
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
add(tok.s, chr(xi))
|
||||
of 'x':
|
||||
var xi = 0
|
||||
inc(L.bufpos)
|
||||
while true:
|
||||
case L.buf[L.bufpos]
|
||||
of '0'..'9':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
of 'a'..'f':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
|
||||
inc(L.bufpos)
|
||||
of 'A'..'F':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
break
|
||||
add(tok.s, chr(xi))
|
||||
elif not allowEmpty:
|
||||
lexMessage(L, errInvalidCharacterConstant)
|
||||
|
||||
@@ -402,7 +437,7 @@ proc getString(L: var TLexer, tok: var TToken) =
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\"':
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
break
|
||||
of CR:
|
||||
pos = nimlexbase.HandleCR(L, pos)
|
||||
@@ -424,7 +459,7 @@ proc getString(L: var TLexer, tok: var TToken) =
|
||||
pos = L.bufpos
|
||||
else:
|
||||
add(tok.s, buf[pos])
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
tok.xkind = pxStrLit
|
||||
|
||||
@@ -435,7 +470,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var c = buf[pos]
|
||||
if c notin SymChars: break
|
||||
add(tok.s, c)
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
tok.xkind = pxSymbol
|
||||
|
||||
@@ -472,7 +507,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.s, "\n#")
|
||||
# skip annoying stars as line prefix: (eg.
|
||||
@@ -508,12 +543,12 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||
if L.inDirective:
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
if buf[pos] in {CR, LF}:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
of ' ', Tabulator:
|
||||
Inc(pos) # newline is special:
|
||||
inc(pos) # newline is special:
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
if L.inDirective:
|
||||
tok.xkind = pxNewLine
|
||||
@@ -556,13 +591,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
of 'b', 'B': getNumber2(L, tok)
|
||||
of '1'..'7': getNumber8(L, tok)
|
||||
else: getNumber(L, tok)
|
||||
elif c in {'1'..'9'}:
|
||||
elif c in {'1'..'9'} or (c == '.' and L.buf[L.bufpos+1] in {'0'..'9'}):
|
||||
getNumber(L, tok)
|
||||
else:
|
||||
case c
|
||||
of ';':
|
||||
tok.xkind = pxSemicolon
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '/':
|
||||
if L.buf[L.bufpos + 1] == '/':
|
||||
scanLineComment(L, tok)
|
||||
@@ -577,9 +612,9 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos)
|
||||
of ',':
|
||||
tok.xkind = pxComma
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '(':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxParLe
|
||||
of '*':
|
||||
inc(L.bufpos)
|
||||
@@ -589,13 +624,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
else:
|
||||
tok.xkind = pxStar
|
||||
of ')':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxParRi
|
||||
of '[':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketLe
|
||||
of ']':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketRi
|
||||
of '.':
|
||||
inc(L.bufpos)
|
||||
@@ -605,10 +640,10 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
else:
|
||||
tok.xkind = pxDot
|
||||
of '{':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxCurlyLe
|
||||
of '}':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxCurlyRi
|
||||
of '+':
|
||||
inc(L.bufpos)
|
||||
@@ -749,4 +784,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
tok.s = $c
|
||||
tok.xkind = pxInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@ proc skipLine(p: var TParser) =
|
||||
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
||||
if p.tok.xkind == pxCurlyLe or
|
||||
(p.tok.xkind == pxSymbol and (
|
||||
declKeyword(p.tok.s) or stmtKeyword(p.tok.s))):
|
||||
declKeyword(p, p.tok.s) or stmtKeyword(p.tok.s))):
|
||||
addSon(tmplDef, statement(p))
|
||||
result = "stmt"
|
||||
elif p.tok.xkind in {pxLineComment, pxNewLine}:
|
||||
@@ -103,7 +103,7 @@ proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
|
||||
m.body.add(tok)
|
||||
of pxDirConc:
|
||||
# just ignore this token: this implements token merging correctly
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
m.body.add(p.tok)
|
||||
# we do not want macro expansion here:
|
||||
@@ -166,7 +166,7 @@ proc parseStmtList(p: var TParser): PNode =
|
||||
of pxDirectiveParLe, pxDirective:
|
||||
case p.tok.s
|
||||
of "else", "endif", "elif": break
|
||||
else: nil
|
||||
else: discard
|
||||
addSon(result, statement(p))
|
||||
|
||||
proc eatEndif(p: var TParser) =
|
||||
@@ -226,7 +226,7 @@ proc skipUntilElifElseEndif(p: var TParser): TEndifMarker =
|
||||
|
||||
proc parseIfdef(p: var TParser): PNode =
|
||||
getTok(p) # skip #ifdef
|
||||
ExpectIdent(p)
|
||||
expectIdent(p)
|
||||
case p.tok.s
|
||||
of "__cplusplus":
|
||||
skipUntilEndif(p)
|
||||
@@ -245,7 +245,7 @@ proc parseIfdef(p: var TParser): PNode =
|
||||
proc parseIfndef(p: var TParser): PNode =
|
||||
result = ast.emptyNode
|
||||
getTok(p) # skip #ifndef
|
||||
ExpectIdent(p)
|
||||
expectIdent(p)
|
||||
if p.tok.s == c2nimSymbol:
|
||||
skipLine(p)
|
||||
case skipUntilElifElseEndif(p)
|
||||
@@ -282,11 +282,11 @@ proc parseIfDir(p: var TParser): PNode =
|
||||
proc parsePegLit(p: var TParser): TPeg =
|
||||
var col = getColumn(p.lex) + 2
|
||||
getTok(p)
|
||||
if p.tok.xkind != pxStrLit: ExpectIdent(p)
|
||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
||||
try:
|
||||
result = parsePeg(
|
||||
pattern = if p.tok.xkind == pxStrLit: p.tok.s else: escapePeg(p.tok.s),
|
||||
filename = p.lex.fileIdx.ToFilename,
|
||||
filename = p.lex.fileIdx.toFilename,
|
||||
line = p.lex.linenumber,
|
||||
col = col)
|
||||
getTok(p)
|
||||
@@ -295,7 +295,7 @@ proc parsePegLit(p: var TParser): TPeg =
|
||||
|
||||
proc parseMangleDir(p: var TParser) =
|
||||
var pattern = parsePegLit(p)
|
||||
if p.tok.xkind != pxStrLit: ExpectIdent(p)
|
||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
||||
p.options.mangleRules.add((pattern, p.tok.s))
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
@@ -323,10 +323,10 @@ proc parseDir(p: var TParser): PNode =
|
||||
discard setOption(p.options, p.tok.s)
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
of "dynlib", "header", "prefix", "suffix":
|
||||
of "dynlib", "header", "prefix", "suffix", "class":
|
||||
var key = p.tok.s
|
||||
getTok(p)
|
||||
if p.tok.xkind != pxStrLit: ExpectIdent(p)
|
||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
||||
discard setOption(p.options, key, p.tok.s)
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
|
||||
240
compiler/c2nim/tests/matrix.h
Normal file
240
compiler/c2nim/tests/matrix.h
Normal file
@@ -0,0 +1,240 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/matrix.h
|
||||
// Purpose: wxTransformMatrix class. NOT YET USED
|
||||
// Author: Chris Breeze, Julian Smart
|
||||
// Modified by: Klaas Holwerda
|
||||
// Created: 01/02/97
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (c) Julian Smart, Chris Breeze
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_MATRIXH__
|
||||
#define _WX_MATRIXH__
|
||||
|
||||
//! headerfiles="matrix.h wx/object.h"
|
||||
#include "wx/object.h"
|
||||
#include "wx/math.h"
|
||||
|
||||
//! codefiles="matrix.cpp"
|
||||
|
||||
// A simple 3x3 matrix. This may be replaced by a more general matrix
|
||||
// class some day.
|
||||
//
|
||||
// Note: this is intended to be used in wxDC at some point to replace
|
||||
// the current system of scaling/translation. It is not yet used.
|
||||
|
||||
#def WXDLLIMPEXP_CORE
|
||||
#header "wxmatrix.h"
|
||||
|
||||
//:definition
|
||||
// A 3x3 matrix to do 2D transformations.
|
||||
// It can be used to map data to window coordinates,
|
||||
// and also for manipulating your own data.
|
||||
// For example drawing a picture (composed of several primitives)
|
||||
// at a certain coordinate and angle within another parent picture.
|
||||
// At all times m_isIdentity is set if the matrix itself is an Identity matrix.
|
||||
// It is used where possible to optimize calculations.
|
||||
class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject<string, string<ubyte>>
|
||||
{
|
||||
public:
|
||||
wxTransformMatrix(void);
|
||||
wxTransformMatrix(const wxTransformMatrix& mat);
|
||||
|
||||
~wxTransformMatrix(void);
|
||||
|
||||
//get the value in the matrix at col,row
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
double GetValue(int col, int row) const;
|
||||
|
||||
//set the value in the matrix at col,row
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
void SetValue(int col, int row, double value);
|
||||
|
||||
void operator = (const wxTransformMatrix& mat);
|
||||
bool operator == (const wxTransformMatrix& mat) const;
|
||||
bool operator != (const module::gah::wxTransformMatrix& mat) const;
|
||||
|
||||
//multiply every element by t
|
||||
wxTransformMatrix& operator*=(const double& t);
|
||||
//divide every element by t
|
||||
wxTransformMatrix& operator/=(const double& t);
|
||||
//add matrix m to this t
|
||||
wxTransformMatrix& operator+=(const wxTransformMatrix& m);
|
||||
//subtract matrix m from this
|
||||
wxTransformMatrix& operator-=(const wxTransformMatrix& m);
|
||||
//multiply matrix m with this
|
||||
wxTransformMatrix& operator*=(const wxTransformMatrix& m);
|
||||
|
||||
// constant operators
|
||||
|
||||
//multiply every element by t and return result
|
||||
wxTransformMatrix operator*(const double& t) const;
|
||||
//divide this matrix by t and return result
|
||||
wxTransformMatrix operator/(const double& t) const;
|
||||
//add matrix m to this and return result
|
||||
wxTransformMatrix operator+(const wxTransformMatrix& m) const;
|
||||
//subtract matrix m from this and return result
|
||||
wxTransformMatrix operator-(const wxTransformMatrix& m) const;
|
||||
//multiply this by matrix m and return result
|
||||
wxTransformMatrix operator*(const wxTransformMatrix& m) const;
|
||||
wxTransformMatrix operator-() const;
|
||||
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
double& operator()(int col, int row);
|
||||
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
double operator()(int col, int row) const;
|
||||
|
||||
// Invert matrix
|
||||
bool Invert(void);
|
||||
|
||||
// Make into identity matrix
|
||||
bool Identity(void);
|
||||
|
||||
// Is the matrix the identity matrix?
|
||||
// Only returns a flag, which is set whenever an operation
|
||||
// is done.
|
||||
inline bool IsIdentity(void) const { return m_isIdentity; }
|
||||
|
||||
// This does an actual check.
|
||||
inline bool IsIdentity1(void) const ;
|
||||
|
||||
//Scale by scale (isotropic scaling i.e. the same in x and y):
|
||||
//!ex:
|
||||
//!code: | scale 0 0 |
|
||||
//!code: matrix' = | 0 scale 0 | x matrix
|
||||
//!code: | 0 0 scale |
|
||||
bool Scale(double scale);
|
||||
|
||||
//Scale with center point and x/y scale
|
||||
//
|
||||
//!ex:
|
||||
//!code: | xs 0 xc(1-xs) |
|
||||
//!code: matrix' = | 0 ys yc(1-ys) | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc);
|
||||
|
||||
// mirror a matrix in x, y
|
||||
//!ex:
|
||||
//!code: | -1 0 0 |
|
||||
//!code: matrix' = | 0 -1 0 | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
wxTransformMatrix<float>& Mirror(bool x=true, bool y=false);
|
||||
// Translate by dx, dy:
|
||||
//!ex:
|
||||
//!code: | 1 0 dx |
|
||||
//!code: matrix' = | 0 1 dy | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
bool Translate(double x, double y);
|
||||
|
||||
// Rotate clockwise by the given number of degrees:
|
||||
//!ex:
|
||||
//!code: | cos sin 0 |
|
||||
//!code: matrix' = | -sin cos 0 | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
bool Rotate(double angle);
|
||||
|
||||
//Rotate counter clockwise with point of rotation
|
||||
//
|
||||
//!ex:
|
||||
//!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)|
|
||||
//!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix
|
||||
//!code: | 0 0 1 |
|
||||
wxTransformMatrix& Rotate(const double &r, const double &x, const double &y);
|
||||
|
||||
// Transform X value from logical to device
|
||||
inline double TransformX(double x) const;
|
||||
|
||||
// Transform Y value from logical to device
|
||||
inline double TransformY(double y) const;
|
||||
|
||||
// Transform a point from logical to device coordinates
|
||||
bool TransformPoint(double x, double y, double& tx, double& ty) const;
|
||||
|
||||
// Transform a point from device to logical coordinates.
|
||||
// Example of use:
|
||||
// wxTransformMatrix mat = dc.GetTransformation();
|
||||
// mat.Invert();
|
||||
// mat.InverseTransformPoint(x, y, x1, y1);
|
||||
// OR (shorthand:)
|
||||
// dc.LogicalToDevice(x, y, x1, y1);
|
||||
// The latter is slightly less efficient if we're doing several
|
||||
// conversions, since the matrix is inverted several times.
|
||||
// N.B. 'this' matrix is the inverse at this point
|
||||
bool InverseTransformPoint(double x, double y, double& tx, double& ty) const;
|
||||
|
||||
double Get_scaleX();
|
||||
double Get_scaleY();
|
||||
double GetRotation();
|
||||
void SetRotation(double rotation);
|
||||
|
||||
|
||||
public:
|
||||
double m_matrix[3][3];
|
||||
bool m_isIdentity;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Chris Breeze reported, that
|
||||
some functions of wxTransformMatrix cannot work because it is not
|
||||
known if he matrix has been inverted. Be careful when using it.
|
||||
*/
|
||||
|
||||
// Transform X value from logical to device
|
||||
// warning: this function can only be used for this purpose
|
||||
// because no rotation is involved when mapping logical to device coordinates
|
||||
// mirror and scaling for x and y will be part of the matrix
|
||||
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
||||
// it in the logical coordinate system, use TransformPoint
|
||||
inline double wxTransformMatrix::TransformX(double x) const
|
||||
{
|
||||
//normally like this, but since no rotation is involved (only mirror and scale)
|
||||
//we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero
|
||||
//(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]))
|
||||
return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0]));
|
||||
}
|
||||
|
||||
// Transform Y value from logical to device
|
||||
// warning: this function can only be used for this purpose
|
||||
// because no rotation is involved when mapping logical to device coordinates
|
||||
// mirror and scaling for x and y will be part of the matrix
|
||||
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
||||
// it in the logical coordinate system, use TransformPoint
|
||||
inline double wxTransformMatrix::TransformY(double y) const
|
||||
{
|
||||
//normally like this, but since no rotation is involved (only mirror and scale)
|
||||
//we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero
|
||||
//(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]))
|
||||
return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1]));
|
||||
}
|
||||
|
||||
|
||||
// Is the matrix the identity matrix?
|
||||
// Each operation checks whether the result is still the identity matrix and sets a flag.
|
||||
inline bool wxTransformMatrix::IsIdentity1(void) const
|
||||
{
|
||||
return
|
||||
( wxIsSameDouble(m_matrix[0][0], 1.0) &&
|
||||
wxIsSameDouble(m_matrix[1][1], 1.0) &&
|
||||
wxIsSameDouble(m_matrix[2][2], 1.0) &&
|
||||
wxIsSameDouble(m_matrix[1][0], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[2][0], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[0][1], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[2][1], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[0][2], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[1][2], 0.0) );
|
||||
}
|
||||
|
||||
// Calculates the determinant of a 2 x 2 matrix
|
||||
inline double wxCalculateDet(double a11, double a21, double a12, double a22)
|
||||
{
|
||||
return a11 * a22 - a12 * a21;
|
||||
}
|
||||
|
||||
#endif // _WX_MATRIXH__
|
||||
33
compiler/c2nim/tests/vincent.c
Normal file
33
compiler/c2nim/tests/vincent.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int rand(void);
|
||||
|
||||
int id2(void) {
|
||||
return (int *)1;
|
||||
}
|
||||
|
||||
int id(void (*f)(void)) {
|
||||
f();
|
||||
((void (*)(int))f)(10);
|
||||
return 10;
|
||||
return (20+1);
|
||||
return (int *)id;
|
||||
}
|
||||
|
||||
int main() {
|
||||
float f = .2,
|
||||
g = 2.,
|
||||
h = 1.0+rand(),
|
||||
i = 1.0e+3;
|
||||
int j, a;
|
||||
for(j = 0, a = 10; j < 0; j++, a++) ;
|
||||
do {
|
||||
printf("howdy");
|
||||
} while(--i, 0);
|
||||
if(1)
|
||||
printf("1"); // error from this comment
|
||||
else
|
||||
printf("2");
|
||||
return '\x00';
|
||||
}
|
||||
3
compiler/c2nim/tests/vincent.h
Normal file
3
compiler/c2nim/tests/vincent.h
Normal file
@@ -0,0 +1,3 @@
|
||||
struct foo {
|
||||
int x,y,z;
|
||||
};
|
||||
416
compiler/canonicalizer.nim
Normal file
416
compiler/canonicalizer.nim
Normal file
@@ -0,0 +1,416 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements the canonalization for the various caching mechanisms.
|
||||
|
||||
import strutils, db_sqlite, md5
|
||||
|
||||
var db: TDbConn
|
||||
|
||||
# We *hash* the relevant information into 128 bit hashes. This should be good
|
||||
# enough to prevent any collisions.
|
||||
|
||||
type
|
||||
TUid = distinct MD5Digest
|
||||
|
||||
# For name mangling we encode these hashes via a variant of base64 (called
|
||||
# 'base64a') and prepend the *primary* identifier to ease the debugging pain.
|
||||
# So a signature like:
|
||||
#
|
||||
# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt)
|
||||
#
|
||||
# is mangled into:
|
||||
# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA
|
||||
#
|
||||
# This is a good compromise between correctness and brevity. ;-)
|
||||
|
||||
const
|
||||
cb64 = [
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
||||
"O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z",
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
|
||||
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"_A", "_B"]
|
||||
|
||||
proc toBase64a(s: cstring, len: int): string =
|
||||
## encodes `s` into base64 representation. After `lineLen` characters, a
|
||||
## `newline` is added.
|
||||
result = newStringOfCap(((len + 2) div 3) * 4)
|
||||
var i = 0
|
||||
while i < s.len - 2:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
let c = ord(s[i+2])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
|
||||
result.add cb64[c and 0x3F]
|
||||
inc(i, 3)
|
||||
if i < s.len-1:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2)]
|
||||
elif i < s.len:
|
||||
let a = ord(s[i])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[(a and 3) shl 4]
|
||||
|
||||
proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
|
||||
|
||||
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
|
||||
|
||||
proc hashSym(c: var MD5Context, s: PSym) =
|
||||
if sfAnon in s.flags or s.kind == skGenericParam:
|
||||
c &= ":anon"
|
||||
else:
|
||||
var it = s.owner
|
||||
while it != nil:
|
||||
hashSym(c, it)
|
||||
c &= "."
|
||||
it = s.owner
|
||||
c &= s.name.s
|
||||
|
||||
proc hashTree(c: var MD5Context, n: PNode) =
|
||||
if n == nil:
|
||||
c &= "\255"
|
||||
return
|
||||
var k = n.kind
|
||||
md5Update(c, cast[cstring](addr(k)), 1)
|
||||
# we really must not hash line information. 'n.typ' is debatable but
|
||||
# shouldn't be necessary for now and avoids potential infinite recursions.
|
||||
case n.kind
|
||||
of nkEmpty, nkNilLit, nkType: discard
|
||||
of nkIdent:
|
||||
c &= n.ident.s
|
||||
of nkSym:
|
||||
hashSym(c, n.sym)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
var v = n.intVal
|
||||
md5Update(c, cast[cstring](addr(v)), sizeof(v))
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
var v = n.floatVal
|
||||
md5Update(c, cast[cstring](addr(v)), sizeof(v))
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
c &= n.strVal
|
||||
else:
|
||||
for i in 0.. <n.len: hashTree(c, n.sons[i])
|
||||
|
||||
proc hashType(c: var MD5Context, t: PType) =
|
||||
# modelled after 'typeToString'
|
||||
if t == nil:
|
||||
c &= "\254"
|
||||
return
|
||||
|
||||
var k = t.kind
|
||||
md5Update(c, cast[cstring](addr(k)), 1)
|
||||
|
||||
if t.sym != nil and sfAnon notin t.sym.flags:
|
||||
# t.n for literals, but not for e.g. objects!
|
||||
if t.kind in {tyFloat, tyInt}: c.hashNode(t.n)
|
||||
c.hashSym(t.sym)
|
||||
|
||||
case t.kind
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
||||
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
|
||||
c.hashType t.sons[i]
|
||||
of tyUserTypeClass:
|
||||
internalAssert t.sym != nil and t.sym.owner != nil
|
||||
c &= t.sym.owner.name.s
|
||||
of tyUserTypeClassInst:
|
||||
let body = t.base
|
||||
c.hashSym body.sym
|
||||
for i in countup(1, sonsLen(t) - 2):
|
||||
c.hashType t.sons[i]
|
||||
of tyFromExpr, tyFieldAccessor:
|
||||
c.hashTree(t.n)
|
||||
of tyArrayConstr:
|
||||
c.hashTree(t.sons[0].n)
|
||||
c.hashType(t.sons[1])
|
||||
of tyTuple:
|
||||
if t.n != nil:
|
||||
assert(sonsLen(t.n) == sonsLen(t))
|
||||
for i in countup(0, sonsLen(t.n) - 1):
|
||||
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 countup(0, sonsLen(t) - 1): c.hashType t.sons[i]
|
||||
of tyRange:
|
||||
c.hashTree(t.n)
|
||||
c.hashType(t.sons[0])
|
||||
of tyProc:
|
||||
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
|
||||
for i in 0.. <t.len: c.hashType(t.sons[i])
|
||||
md5Update(c, cast[cstring](addr(t.callConv)), 1)
|
||||
|
||||
if tfNoSideEffect in t.flags: c &= ".noSideEffect"
|
||||
if tfThread in t.flags: c &= ".thread"
|
||||
else:
|
||||
for i in 0.. <t.len: c.hashType(t.sons[i])
|
||||
if tfShared in t.flags: c &= "shared"
|
||||
if tfNotNil in t.flags: c &= "not nil"
|
||||
|
||||
proc canonConst(n: PNode): TUid =
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
c.hashTree(n)
|
||||
c.hashType(n.typ)
|
||||
md5Final(c, MD5Digest(result))
|
||||
|
||||
proc canonSym(s: PSym): TUid =
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
c.hashSym(s)
|
||||
md5Final(c, MD5Digest(result))
|
||||
|
||||
proc pushType(w: PRodWriter, t: PType) =
|
||||
# check so that the stack does not grow too large:
|
||||
if iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
w.tstack.add(t)
|
||||
|
||||
proc pushSym(w: PRodWriter, s: PSym) =
|
||||
# check so that the stack does not grow too large:
|
||||
if iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
w.sstack.add(s)
|
||||
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
result: var string) =
|
||||
if n == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("()")
|
||||
return
|
||||
result.add('(')
|
||||
encodeVInt(ord(n.kind), result)
|
||||
# we do not write comments for now
|
||||
# Line information takes easily 20% or more of the filesize! Therefore we
|
||||
# omit line information if it is the same as the father's line information:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
encodeVInt(n.info.line, result)
|
||||
result.add(',')
|
||||
encodeVInt(fileIdx(w, toFilename(n.info)), result)
|
||||
elif fInfo.line != n.info.line:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
encodeVInt(n.info.line, result)
|
||||
elif fInfo.col != n.info.col:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
var f = n.flags * PersistentNodeFlags
|
||||
if f != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](f), result)
|
||||
if n.typ != nil:
|
||||
result.add('^')
|
||||
encodeVInt(n.typ.id, result)
|
||||
pushType(w, n.typ)
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
if n.intVal != 0:
|
||||
result.add('!')
|
||||
encodeVBiggestInt(n.intVal, result)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if n.floatVal != 0.0:
|
||||
result.add('!')
|
||||
encodeStr($n.floatVal, result)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if n.strVal != "":
|
||||
result.add('!')
|
||||
encodeStr(n.strVal, result)
|
||||
of nkIdent:
|
||||
result.add('!')
|
||||
encodeStr(n.ident.s, result)
|
||||
of nkSym:
|
||||
result.add('!')
|
||||
encodeVInt(n.sym.id, result)
|
||||
pushSym(w, n.sym)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
var oldLen = result.len
|
||||
result.add('<')
|
||||
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
|
||||
if loc.s != low(loc.s):
|
||||
add(result, '*')
|
||||
encodeVInt(ord(loc.s), result)
|
||||
if loc.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](loc.flags), result)
|
||||
if loc.t != nil:
|
||||
add(result, '^')
|
||||
encodeVInt(cast[int32](loc.t.id), result)
|
||||
pushType(w, loc.t)
|
||||
if loc.r != nil:
|
||||
add(result, '!')
|
||||
encodeStr(ropeToStr(loc.r), result)
|
||||
if loc.a != 0:
|
||||
add(result, '?')
|
||||
encodeVInt(loc.a, result)
|
||||
if oldLen + 1 == result.len:
|
||||
# no data was necessary, so remove the '<' again:
|
||||
setLen(result, oldLen)
|
||||
else:
|
||||
add(result, '>')
|
||||
|
||||
proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
if t == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("[]")
|
||||
return
|
||||
# we need no surrounding [] here because the type is in a line of its own
|
||||
if t.kind == tyForward: internalError("encodeType: tyForward")
|
||||
# for the new rodfile viewer we use a preceeding [ so that the data section
|
||||
# can easily be disambiguated:
|
||||
add(result, '[')
|
||||
encodeVInt(ord(t.kind), result)
|
||||
add(result, '+')
|
||||
encodeVInt(t.id, result)
|
||||
if t.n != nil:
|
||||
encodeNode(w, unknownLineInfo(), t.n, result)
|
||||
if t.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](t.flags), result)
|
||||
if t.callConv != low(t.callConv):
|
||||
add(result, '?')
|
||||
encodeVInt(ord(t.callConv), result)
|
||||
if t.owner != nil:
|
||||
add(result, '*')
|
||||
encodeVInt(t.owner.id, result)
|
||||
pushSym(w, t.owner)
|
||||
if t.sym != nil:
|
||||
add(result, '&')
|
||||
encodeVInt(t.sym.id, result)
|
||||
pushSym(w, t.sym)
|
||||
if t.size != - 1:
|
||||
add(result, '/')
|
||||
encodeVBiggestInt(t.size, result)
|
||||
if t.align != 2:
|
||||
add(result, '=')
|
||||
encodeVInt(t.align, result)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
add(result, "^()")
|
||||
else:
|
||||
add(result, '^')
|
||||
encodeVInt(t.sons[i].id, result)
|
||||
pushType(w, t.sons[i])
|
||||
|
||||
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
add(result, '|')
|
||||
encodeVInt(ord(lib.kind), result)
|
||||
add(result, '|')
|
||||
encodeStr(ropeToStr(lib.name), result)
|
||||
add(result, '|')
|
||||
encodeNode(w, info, lib.path, result)
|
||||
|
||||
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||
if s == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("{}")
|
||||
return
|
||||
# we need no surrounding {} here because the symbol is in a line of its own
|
||||
encodeVInt(ord(s.kind), result)
|
||||
result.add('+')
|
||||
encodeVInt(s.id, result)
|
||||
result.add('&')
|
||||
encodeStr(s.name.s, result)
|
||||
if s.typ != nil:
|
||||
result.add('^')
|
||||
encodeVInt(s.typ.id, result)
|
||||
pushType(w, s.typ)
|
||||
result.add('?')
|
||||
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
|
||||
result.add(',')
|
||||
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
|
||||
result.add(',')
|
||||
encodeVInt(fileIdx(w, toFilename(s.info)), result)
|
||||
if s.owner != nil:
|
||||
result.add('*')
|
||||
encodeVInt(s.owner.id, result)
|
||||
pushSym(w, s.owner)
|
||||
if s.flags != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](s.flags), result)
|
||||
if s.magic != mNone:
|
||||
result.add('@')
|
||||
encodeVInt(ord(s.magic), result)
|
||||
if s.options != w.options:
|
||||
result.add('!')
|
||||
encodeVInt(cast[int32](s.options), result)
|
||||
if s.position != 0:
|
||||
result.add('%')
|
||||
encodeVInt(s.position, result)
|
||||
if s.offset != - 1:
|
||||
result.add('`')
|
||||
encodeVInt(s.offset, result)
|
||||
encodeLoc(w, s.loc, result)
|
||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||
if s.constraint != nil:
|
||||
add(result, '#')
|
||||
encodeNode(w, unknownLineInfo(), s.constraint, result)
|
||||
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
# we used to attempt to save space here by only storing a dummy AST if
|
||||
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
||||
# make that unfeasible nowadays:
|
||||
encodeNode(w, s.info, s.ast, result)
|
||||
|
||||
|
||||
proc createDb() =
|
||||
db.exec(sql"""
|
||||
create table if not exists Module(
|
||||
id integer primary key,
|
||||
name varchar(256) not null,
|
||||
fullpath varchar(256) not null,
|
||||
interfHash varchar(256) not null,
|
||||
fullHash varchar(256) not null,
|
||||
|
||||
created timestamp not null default (DATETIME('now')),
|
||||
);""")
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists Symbol(
|
||||
id integer primary key,
|
||||
module integer not null,
|
||||
name varchar(max) not null,
|
||||
data varchar(max) not null,
|
||||
created timestamp not null default (DATETIME('now')),
|
||||
|
||||
foreign key (module) references module(id)
|
||||
);""")
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists Type(
|
||||
id integer primary key,
|
||||
module integer not null,
|
||||
name varchar(max) not null,
|
||||
data varchar(max) not null,
|
||||
created timestamp not null default (DATETIME('now')),
|
||||
|
||||
foreign key (module) references module(id)
|
||||
);""")
|
||||
|
||||
|
||||
#db.exec(sql"""
|
||||
# --create unique index if not exists TsstNameIx on TestResult(name);
|
||||
# """, [])
|
||||
|
||||
@@ -73,7 +73,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
|
||||
result = false
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isInCurrentFrame(p, n.sons[0])
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||
var a: TLoc
|
||||
@@ -88,7 +88,7 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
|
||||
of tyArray, tyArrayConstr:
|
||||
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
|
||||
else: InternalError("openArrayLoc: " & typeToString(a.t))
|
||||
else: internalError("openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
proc genArgStringToCString(p: BProc,
|
||||
n: PNode): PRope {.inline.} =
|
||||
@@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
proc addComma(r: PRope): PRope =
|
||||
result = if r == nil: r else: con(r, ~", ")
|
||||
|
||||
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
|
||||
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
|
||||
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri.sons[0], op)
|
||||
var pl: PRope
|
||||
@@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if i < length - 1: app(pl, ~", ")
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
||||
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
||||
|
||||
let rawProc = getRawProcType(p, typ)
|
||||
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(typ.sons[0]):
|
||||
if sonsLen(ri) > 1: app(pl, ~", ")
|
||||
@@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.t, OnUnknown)
|
||||
list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
|
||||
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
genCallPattern()
|
||||
@@ -243,7 +245,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
for i in countup(3, length-1):
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if i >= sonsLen(typ):
|
||||
InternalError(ri.info, "varargs for objective C method?")
|
||||
internalError(ri.info, "varargs for objective C method?")
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
var param = typ.n.sons[i].sym
|
||||
app(pl, ~" ")
|
||||
@@ -290,6 +292,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
|
||||
genNamedParamCall(p, e, d)
|
||||
else:
|
||||
genPrefixCall(p, nil, e, d)
|
||||
postStmtActions(p)
|
||||
when false:
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
|
||||
@@ -303,6 +306,7 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genNamedParamCall(p, ri, d)
|
||||
else:
|
||||
genPrefixCall(p, le, ri, d)
|
||||
postStmtActions(p)
|
||||
when false:
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -108,7 +108,7 @@ proc genMergeInfo*(m: BModule): PRope =
|
||||
s.add("labels:")
|
||||
encodeVInt(m.labels, s)
|
||||
s.add(" hasframe:")
|
||||
encodeVInt(ord(m.FrameDeclared), s)
|
||||
encodeVInt(ord(m.frameDeclared), s)
|
||||
s.add(tnl)
|
||||
s.add("*/")
|
||||
result = s.toRope
|
||||
@@ -119,8 +119,8 @@ proc skipWhite(L: var TBaseLexer) =
|
||||
var pos = L.bufpos
|
||||
while true:
|
||||
case ^pos
|
||||
of CR: pos = nimlexbase.HandleCR(L, pos)
|
||||
of LF: pos = nimlexbase.HandleLF(L, pos)
|
||||
of CR: pos = nimlexbase.handleCR(L, pos)
|
||||
of LF: pos = nimlexbase.handleLF(L, pos)
|
||||
of ' ': inc pos
|
||||
else: break
|
||||
L.bufpos = pos
|
||||
@@ -129,8 +129,8 @@ proc skipUntilCmd(L: var TBaseLexer) =
|
||||
var pos = L.bufpos
|
||||
while true:
|
||||
case ^pos
|
||||
of CR: pos = nimlexbase.HandleCR(L, pos)
|
||||
of LF: pos = nimlexbase.HandleLF(L, pos)
|
||||
of CR: pos = nimlexbase.handleCR(L, pos)
|
||||
of LF: pos = nimlexbase.handleLF(L, pos)
|
||||
of '\0': break
|
||||
of '/':
|
||||
if ^(pos+1) == '*' and ^(pos+2) == '\t':
|
||||
@@ -145,33 +145,6 @@ proc atEndMark(buf: cstring, pos: int): bool =
|
||||
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
|
||||
result = s == NimMergeEndMark.len
|
||||
|
||||
when false:
|
||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
result = newMutableRope(30_000)
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR:
|
||||
pos = nimlexbase.HandleCR(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
of LF:
|
||||
pos = nimlexbase.HandleLF(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
of '\0':
|
||||
InternalError("ccgmerge: expected: " & NimMergeEndMark)
|
||||
break
|
||||
else:
|
||||
if atEndMark(buf, pos):
|
||||
inc pos, NimMergeEndMark.len
|
||||
break
|
||||
result.data.add(buf[pos])
|
||||
inc pos
|
||||
L.bufpos = pos
|
||||
freezeMutableRope(result)
|
||||
|
||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
@@ -179,15 +152,15 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR:
|
||||
pos = nimlexbase.HandleCR(L, pos)
|
||||
pos = nimlexbase.handleCR(L, pos)
|
||||
buf = L.buf
|
||||
r.add(tnl)
|
||||
of LF:
|
||||
pos = nimlexbase.HandleLF(L, pos)
|
||||
pos = nimlexbase.handleLF(L, pos)
|
||||
buf = L.buf
|
||||
r.add(tnl)
|
||||
of '\0':
|
||||
InternalError("ccgmerge: expected: " & NimMergeEndMark)
|
||||
internalError("ccgmerge: expected: " & NimMergeEndMark)
|
||||
break
|
||||
else:
|
||||
if atEndMark(buf, pos):
|
||||
@@ -208,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
|
||||
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
|
||||
L.bufpos = pos + 1 # skip ':'
|
||||
|
||||
proc NewFakeType(id: int): PType =
|
||||
proc newFakeType(id: int): PType =
|
||||
new(result)
|
||||
result.id = id
|
||||
|
||||
@@ -224,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
|
||||
# XXX little hack: we create a "fake" type object with the correct Id
|
||||
# better would be to adapt the data structure to not even store the
|
||||
# object as key, but only the Id
|
||||
IdTablePut(result, newFakeType(key), value.toRope)
|
||||
idTablePut(result, newFakeType(key), value.toRope)
|
||||
inc L.bufpos
|
||||
|
||||
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
|
||||
@@ -249,14 +222,14 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||
of "declared": readIntSet(L, m.declaredThings)
|
||||
of "typeInfo": readIntSet(L, m.typeInfoMarker)
|
||||
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
|
||||
of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
||||
else: InternalError("ccgmerge: unkown key: " & k)
|
||||
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
||||
else: internalError("ccgmerge: unkown key: " & k)
|
||||
|
||||
when not defined(nimhygiene):
|
||||
{.pragma: inject.}
|
||||
|
||||
template withCFile(cfilename: string, body: stmt) {.immediate.} =
|
||||
var s = LLStreamOpen(cfilename, fmRead)
|
||||
var s = llStreamOpen(cfilename, fmRead)
|
||||
if s == nil: return
|
||||
var L {.inject.}: TBaseLexer
|
||||
openBaseLexer(L, s)
|
||||
@@ -285,7 +258,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
|
||||
withCFile(cfilename):
|
||||
readKey(L, k)
|
||||
if k == "NIM_merge_INFO":
|
||||
nil
|
||||
discard
|
||||
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
|
||||
inc(L.bufpos, 2)
|
||||
# read back into section
|
||||
@@ -300,9 +273,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
|
||||
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
|
||||
m.p[TCProcSection(sectionB)] = verbatim
|
||||
else:
|
||||
InternalError("ccgmerge: unknown section: " & k)
|
||||
internalError("ccgmerge: unknown section: " & k)
|
||||
else:
|
||||
InternalError("ccgmerge: '*/' expected")
|
||||
internalError("ccgmerge: '*/' expected")
|
||||
|
||||
proc mergeRequired*(m: BModule): bool =
|
||||
for i in cfsHeaders..cfsProcs:
|
||||
@@ -323,4 +296,3 @@ proc mergeFiles*(cfilename: string, m: BModule) =
|
||||
m.s[i] = con(old.f[i], m.s[i])
|
||||
for i in low(TCProcSection)..high(TCProcSection):
|
||||
m.initProc.s(i) = con(old.p[i], m.initProc.s(i))
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const
|
||||
# above X strings a hash-switch for strings is generated
|
||||
|
||||
proc registerGcRoot(p: BProc, v: PSym) =
|
||||
if gSelectedGc in {gcMarkAndSweep, gcGenerational} and
|
||||
if gSelectedGC in {gcMarkAndSweep, gcGenerational} and
|
||||
containsGarbageCollectedRef(v.loc.t):
|
||||
# we register a specialized marked proc here; this has the advantage
|
||||
# that it works out of the box for thread local storage then :-)
|
||||
@@ -26,7 +26,7 @@ proc registerGcRoot(p: BProc, v: PSym) =
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple")
|
||||
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
|
||||
var L = sonsLen(n)
|
||||
genLineDir(p, n)
|
||||
initLocExpr(p, n.sons[L-1], tup)
|
||||
@@ -45,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
if t.kind == tyTuple:
|
||||
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
|
||||
else:
|
||||
if t.n.sons[i].kind != nkSym: InternalError(n.info, "genVarTuple")
|
||||
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
|
||||
field.r = ropef("$1.$2",
|
||||
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
||||
putLocIntoDest(p, v.loc, field)
|
||||
@@ -62,9 +62,10 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
|
||||
lineCg(p, cpsStmts, start, args)
|
||||
inc(p.labels)
|
||||
result = len(p.blocks)
|
||||
setlen(p.blocks, result + 1)
|
||||
setLen(p.blocks, result + 1)
|
||||
p.blocks[result].id = p.labels
|
||||
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
|
||||
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
|
||||
|
||||
proc assignLabel(b: var TBlock): PRope {.inline.} =
|
||||
b.label = con("LA", b.id.toRope)
|
||||
@@ -81,7 +82,7 @@ proc endBlock(p: BProc, blockEnd: PRope) =
|
||||
let topBlock = p.blocks.len-1
|
||||
# the block is merged into the parent block
|
||||
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
||||
setlen(p.blocks, topBlock)
|
||||
setLen(p.blocks, topBlock)
|
||||
# this is done after the block is popped so $n is
|
||||
# properly indented when pretty printing is enabled
|
||||
line(p, cpsStmts, blockEnd)
|
||||
@@ -126,7 +127,7 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
|
||||
p.BeforeRetNeeded = true
|
||||
p.beforeRetNeeded = true
|
||||
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
|
||||
for i in 0 .. lastOrd(n.sons[0].typ):
|
||||
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)])
|
||||
@@ -137,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) =
|
||||
if n.sons[0].kind == nkClosure:
|
||||
# XXX this produces quite inefficient code!
|
||||
initLocExpr(p, n.sons[0].sons[1], a)
|
||||
lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)])
|
||||
lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
|
||||
else:
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
# the environment is guaranteed to contain the 'state' field at offset 0:
|
||||
@@ -151,7 +152,8 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
var targetProc = p
|
||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
||||
if sfGlobal in v.flags:
|
||||
if v.owner.kind != skModule:
|
||||
if sfPure in v.flags:
|
||||
# v.owner.kind != skModule:
|
||||
targetProc = p.module.preInitProc
|
||||
assignGlobalVar(targetProc, v)
|
||||
# XXX: be careful here.
|
||||
@@ -199,7 +201,7 @@ proc genConstStmt(p: BProc, t: PNode) =
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
var it = t.sons[i]
|
||||
if it.kind == nkCommentStmt: continue
|
||||
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
|
||||
if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
|
||||
var c = it.sons[0].sym
|
||||
if c.typ.containsCompileTimeOnly: continue
|
||||
if sfFakeConst in c.flags:
|
||||
@@ -231,73 +233,162 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
# Lend:
|
||||
var
|
||||
a: TLoc
|
||||
Lelse: TLabel
|
||||
lelse: TLabel
|
||||
if not isEmptyType(n.typ) and d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
genLineDir(p, n)
|
||||
let Lend = getLabel(p)
|
||||
let lend = getLabel(p)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
if it.len == 2:
|
||||
when newScopeForIf: startBlock(p)
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
Lelse = getLabel(p)
|
||||
lelse = getLabel(p)
|
||||
inc(p.labels)
|
||||
lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
|
||||
"br i1 $1, label %LOC$3, label %$2$nLOC$3: $n",
|
||||
[rdLoc(a), Lelse, toRope(p.labels)])
|
||||
[rdLoc(a), lelse, toRope(p.labels)])
|
||||
when not newScopeForIf: startBlock(p)
|
||||
expr(p, it.sons[1], d)
|
||||
endBlock(p)
|
||||
if sonsLen(n) > 1:
|
||||
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [Lend])
|
||||
fixLabel(p, Lelse)
|
||||
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend])
|
||||
fixLabel(p, lelse)
|
||||
elif it.len == 1:
|
||||
startBlock(p)
|
||||
expr(p, it.sons[0], d)
|
||||
endBlock(p)
|
||||
else: internalError(n.info, "genIf()")
|
||||
if sonsLen(n) > 1: fixLabel(p, Lend)
|
||||
if sonsLen(n) > 1: fixLabel(p, lend)
|
||||
|
||||
|
||||
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,
|
||||
|
||||
proc blockLeaveActions(p: BProc, howMany: int) =
|
||||
var L = p.nestedTryStmts.len
|
||||
# danger of endless recursion! we workaround this here by a temp stack
|
||||
var stack: seq[PNode]
|
||||
newSeq(stack, howMany)
|
||||
for i in countup(1, howMany):
|
||||
stack[i-1] = p.nestedTryStmts[L-i]
|
||||
setLen(p.nestedTryStmts, L-howMany)
|
||||
newSeq(stack, 0)
|
||||
|
||||
var alreadyPoppedCnt = p.inExceptBlock
|
||||
for tryStmt in items(stack):
|
||||
for i in countup(1, howManyTrys):
|
||||
|
||||
if gCmd != cmdCompileToCpp:
|
||||
# Pop safe points generated by try
|
||||
if alreadyPoppedCnt > 0:
|
||||
dec alreadyPoppedCnt
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
|
||||
# Pop this try-stmt of the list of nested trys
|
||||
# so we don't infinite recurse on it in the next step.
|
||||
var tryStmt = p.nestedTryStmts.pop
|
||||
stack.add(tryStmt)
|
||||
|
||||
# Find finally-stmt for this try-stmt
|
||||
# and generate a copy of its sons
|
||||
var finallyStmt = lastSon(tryStmt)
|
||||
if finallyStmt.kind == nkFinally:
|
||||
genStmts(p, finallyStmt.sons[0])
|
||||
|
||||
# push old elements again:
|
||||
for i in countdown(howMany-1, 0):
|
||||
for i in countdown(howManyTrys-1, 0):
|
||||
p.nestedTryStmts.add(stack[i])
|
||||
|
||||
if gCmd != cmdCompileToCpp:
|
||||
for i in countdown(p.inExceptBlock-1, 0):
|
||||
# Pop exceptions that was handled by the
|
||||
# except-blocks we are in
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
|
||||
proc genReturnStmt(p: BProc, t: PNode) =
|
||||
p.beforeRetNeeded = true
|
||||
genLineDir(p, t)
|
||||
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
|
||||
blockLeaveActions(p, min(1, p.nestedTryStmts.len))
|
||||
blockLeaveActions(p,
|
||||
howManyTrys = p.nestedTryStmts.len,
|
||||
howManyExcepts = p.inExceptBlock)
|
||||
if (p.finallySafePoints.len > 0):
|
||||
# If we're in a finally block, and we came here by exception
|
||||
# consume it before we return.
|
||||
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
|
||||
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
||||
|
||||
proc genComputedGoto(p: BProc; n: PNode) =
|
||||
# first pass: Generate array of computed labels:
|
||||
var casePos = -1
|
||||
var arraySize: int
|
||||
for i in 0 .. <n.len:
|
||||
let it = n.sons[i]
|
||||
if it.kind == nkCaseStmt:
|
||||
if lastSon(it).kind != nkOfBranch:
|
||||
localError(it.info,
|
||||
"case statement must be exhaustive for computed goto"); return
|
||||
casePos = i
|
||||
let aSize = lengthOrd(it.sons[0].typ)
|
||||
if aSize > 10_000:
|
||||
localError(it.info,
|
||||
"case statement has too many cases for computed goto"); return
|
||||
arraySize = aSize.int
|
||||
if firstOrd(it.sons[0].typ) != 0:
|
||||
localError(it.info,
|
||||
"case statement has to start at 0 for computed goto"); return
|
||||
if casePos < 0:
|
||||
localError(n.info, "no case statement found for computed goto"); return
|
||||
var id = p.labels+1
|
||||
inc p.labels, arraySize+1
|
||||
let tmp = ropef("TMP$1", id.toRope)
|
||||
var gotoArray = ropef("static void* $#[$#] = {", tmp, arraySize.toRope)
|
||||
for i in 1..arraySize-1:
|
||||
gotoArray.appf("&&TMP$#, ", (id+i).toRope)
|
||||
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
|
||||
line(p, cpsLocals, gotoArray)
|
||||
|
||||
let topBlock = p.blocks.len-1
|
||||
let oldBody = p.blocks[topBlock].sections[cpsStmts]
|
||||
p.blocks[topBlock].sections[cpsStmts] = nil
|
||||
|
||||
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
|
||||
let tailB = p.blocks[topBlock].sections[cpsStmts]
|
||||
|
||||
p.blocks[topBlock].sections[cpsStmts] = nil
|
||||
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
|
||||
let tailA = p.blocks[topBlock].sections[cpsStmts]
|
||||
|
||||
p.blocks[topBlock].sections[cpsStmts] = oldBody.con(tailA)
|
||||
|
||||
let caseStmt = n.sons[casePos]
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt.sons[0], a)
|
||||
# first goto:
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
||||
|
||||
for i in 1 .. <caseStmt.len:
|
||||
startBlock(p)
|
||||
let it = caseStmt.sons[i]
|
||||
for j in 0 .. it.len-2:
|
||||
if it.sons[j].kind == nkRange:
|
||||
localError(it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it.sons[j])
|
||||
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
|
||||
genStmts(p, it.lastSon)
|
||||
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
|
||||
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
|
||||
app(p.s(cpsStmts), tailB)
|
||||
app(p.s(cpsStmts), tailA)
|
||||
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt.sons[0], a)
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
||||
endBlock(p)
|
||||
|
||||
proc genWhileStmt(p: BProc, t: PNode) =
|
||||
# we don't generate labels here as for example GCC would produce
|
||||
# significantly worse code
|
||||
var
|
||||
a: TLoc
|
||||
Labl: TLabel
|
||||
labl: TLabel
|
||||
assert(sonsLen(t) == 2)
|
||||
inc(p.withinLoop)
|
||||
genLineDir(p, t)
|
||||
@@ -309,7 +400,15 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
|
||||
let label = assignLabel(p.blocks[p.breakIdx])
|
||||
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
|
||||
genStmts(p, t.sons[1])
|
||||
var loopBody = t.sons[1]
|
||||
if loopBody.stmtsContainPragma(wComputedGoto) and
|
||||
hasComputedGoto in CC[cCompiler].props:
|
||||
# for closure support weird loop bodies are generated:
|
||||
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
|
||||
loopBody = loopBody.sons[1]
|
||||
genComputedGoto(p, loopBody)
|
||||
else:
|
||||
genStmts(p, loopBody)
|
||||
|
||||
if optProfiler in p.options:
|
||||
# invoke at loop body exit:
|
||||
@@ -338,7 +437,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
preserveBreakIdx:
|
||||
let forLoopVar = t.sons[0].sym
|
||||
var rangeA, rangeB: TLoc
|
||||
assignLocalVar(P, forLoopVar)
|
||||
assignLocalVar(p, forLoopVar)
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t.sons[1]
|
||||
@@ -370,9 +469,11 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||
# an unnamed 'break' can only break a loop after 'transf' pass:
|
||||
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
|
||||
if idx < 0 or not p.blocks[idx].isLoop:
|
||||
InternalError(t.info, "no loop to break")
|
||||
internalError(t.info, "no loop to break")
|
||||
let label = assignLabel(p.blocks[idx])
|
||||
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
|
||||
blockLeaveActions(p,
|
||||
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
|
||||
p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
|
||||
genLineDir(p, t)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [label])
|
||||
|
||||
@@ -391,7 +492,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
genSimpleBlock(p, finallyBlock.sons[0])
|
||||
if t.sons[0].kind != nkEmpty:
|
||||
var a: TLoc
|
||||
InitLocExpr(p, t.sons[0], a)
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
var e = rdLoc(a)
|
||||
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
|
||||
genLineDir(p, t)
|
||||
@@ -421,16 +522,16 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
labId, until: int): TLabel =
|
||||
var Lend = getLabel(p)
|
||||
var lend = getLabel(p)
|
||||
for i in 1..until:
|
||||
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
var length = sonsLen(t.sons[i])
|
||||
exprBlock(p, t.sons[i].sons[length - 1], d)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [Lend])
|
||||
lineF(p, cpsStmts, "goto $1;$n", [lend])
|
||||
else:
|
||||
exprBlock(p, t.sons[i].sons[0], d)
|
||||
result = Lend
|
||||
result = lend
|
||||
|
||||
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr,
|
||||
@@ -457,8 +558,8 @@ proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
var Lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
|
||||
fixLabel(p, Lend)
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
|
||||
fixLabel(p, lend)
|
||||
|
||||
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
branches: var openArray[PRope]) =
|
||||
@@ -502,25 +603,25 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
|
||||
# third pass: generate statements
|
||||
var Lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
|
||||
fixLabel(p, Lend)
|
||||
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(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 countup(0, sonsLen(b)-2):
|
||||
# last son is block
|
||||
if (b.sons[i].Kind == nkRange) and
|
||||
if (b.sons[i].kind == nkRange) and
|
||||
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
|
||||
return true
|
||||
|
||||
proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
for i in 1..n.len-1:
|
||||
var branch = n[i]
|
||||
var stmtBlock = lastSon(branch)
|
||||
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
|
||||
result = i
|
||||
elif hasSwitchRange notin CC[ccompiler].props:
|
||||
elif hasSwitchRange notin CC[cCompiler].props:
|
||||
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
|
||||
result = i
|
||||
|
||||
@@ -528,7 +629,7 @@ proc genCaseRange(p: BProc, branch: PNode) =
|
||||
var length = branch.len
|
||||
for j in 0 .. length-2:
|
||||
if branch[j].kind == nkRange:
|
||||
if hasSwitchRange in CC[ccompiler].props:
|
||||
if hasSwitchRange in CC[cCompiler].props:
|
||||
lineF(p, cpsStmts, "case $1 ... $2:$n", [
|
||||
genLiteral(p, branch[j][0]),
|
||||
genLiteral(p, branch[j][1])])
|
||||
@@ -536,18 +637,18 @@ proc genCaseRange(p: BProc, branch: PNode) =
|
||||
var v = copyNode(branch[j][0])
|
||||
while v.intVal <= branch[j][1].intVal:
|
||||
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
|
||||
Inc(v.intVal)
|
||||
inc(v.intVal)
|
||||
else:
|
||||
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])])
|
||||
|
||||
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
# analyse 'case' statement:
|
||||
var splitPoint = IfSwitchSplitPoint(p, n)
|
||||
var splitPoint = ifSwitchSplitPoint(p, n)
|
||||
|
||||
# generate if part (might be empty):
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
var Lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
|
||||
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
|
||||
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
eqFormat = "if ($1 == $2) goto $3;$n",
|
||||
splitPoint, a) else: nil
|
||||
@@ -566,10 +667,10 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
hasDefault = true
|
||||
exprBlock(p, branch.lastSon, d)
|
||||
lineF(p, cpsStmts, "break;$n")
|
||||
if (hasAssume in CC[ccompiler].props) and not hasDefault:
|
||||
if (hasAssume in CC[cCompiler].props) and not hasDefault:
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n")
|
||||
lineF(p, cpsStmts, "}$n")
|
||||
if Lend != nil: fixLabel(p, Lend)
|
||||
if lend != nil: fixLabel(p, lend)
|
||||
|
||||
proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
genLineDir(p, t)
|
||||
@@ -628,7 +729,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
expr(p, t.sons[0], d)
|
||||
length = sonsLen(t)
|
||||
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
|
||||
if optStackTrace in p.Options:
|
||||
if optStackTrace in p.options:
|
||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
|
||||
inc p.inExceptBlock
|
||||
i = 1
|
||||
@@ -701,6 +802,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
#
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
|
||||
genLineDir(p, t)
|
||||
var safePoint = getTempName()
|
||||
discard cgsym(p.module, "E_Base")
|
||||
@@ -715,7 +817,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
endBlock(p)
|
||||
startBlock(p, "else {$n")
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
if optStackTrace in p.Options:
|
||||
if optStackTrace in p.options:
|
||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
|
||||
inc p.inExceptBlock
|
||||
var i = 1
|
||||
@@ -748,35 +850,57 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
discard pop(p.nestedTryStmts)
|
||||
endBlock(p) # end of else block
|
||||
if i < length and t.sons[i].kind == nkFinally:
|
||||
p.finallySafePoints.add(safePoint)
|
||||
exprBlock(p, t.sons[i].sons[0], d)
|
||||
discard pop(p.finallySafePoints)
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope =
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
case t.sons[i].Kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
app(result, t.sons[i].strVal)
|
||||
of nkSym:
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||
var res = ""
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
case t.sons[i].kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
res.add(t.sons[i].strVal)
|
||||
of nkSym:
|
||||
var sym = t.sons[i].sym
|
||||
if sym.kind in {skProc, skIterator, skMethod}:
|
||||
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[i], a)
|
||||
app(result, rdLoc(a))
|
||||
else:
|
||||
res.add(rdLoc(a).ropeToStr)
|
||||
else:
|
||||
var r = sym.loc.r
|
||||
if r == nil:
|
||||
# if no name has already been given,
|
||||
# it doesn't matter much:
|
||||
r = mangleName(sym)
|
||||
sym.loc.r = r # but be consequent!
|
||||
app(result, r)
|
||||
else: InternalError(t.sons[i].info, "genAsmOrEmitStmt()")
|
||||
res.add(r.ropeToStr)
|
||||
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
|
||||
|
||||
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
|
||||
for x in splitLines(res):
|
||||
var j = 0
|
||||
while x[j] in {' ', '\t'}: inc(j)
|
||||
if x[j] == ':' and x[j+1] == '"' or x[j] == '"':
|
||||
# some clobber register list:
|
||||
app(result, x); app(result, tnl)
|
||||
elif x[j] != '\0':
|
||||
# ignore empty lines
|
||||
app(result, "\"")
|
||||
app(result, x)
|
||||
app(result, "\\n\"\n")
|
||||
else:
|
||||
result = res.toRope
|
||||
|
||||
proc genAsmStmt(p: BProc, t: PNode) =
|
||||
assert(t.kind == nkAsmStmt)
|
||||
genLineDir(p, t)
|
||||
var s = genAsmOrEmitStmt(p, t)
|
||||
lineF(p, cpsStmts, CC[ccompiler].asmStmtFrmt, [s])
|
||||
var s = genAsmOrEmitStmt(p, t, isAsmStmt=true)
|
||||
if p.prc == nil:
|
||||
# top level asm statement?
|
||||
appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
|
||||
else:
|
||||
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
|
||||
|
||||
proc genEmit(p: BProc, t: PNode) =
|
||||
genLineDir(p, t)
|
||||
@@ -793,7 +917,7 @@ var
|
||||
|
||||
proc genBreakPoint(p: BProc, t: PNode) =
|
||||
var name: string
|
||||
if optEndb in p.Options:
|
||||
if optEndb in p.options:
|
||||
if t.kind == nkExprColonExpr:
|
||||
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
|
||||
name = normalize(t.sons[1].strVal)
|
||||
@@ -807,7 +931,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
|
||||
makeCString(name)])
|
||||
|
||||
proc genWatchpoint(p: BProc, n: PNode) =
|
||||
if optEndb notin p.Options: return
|
||||
if optEndb notin p.options: return
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[1], a)
|
||||
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
@@ -821,10 +945,15 @@ proc genPragma(p: BProc, n: PNode) =
|
||||
case whichPragma(it)
|
||||
of wEmit: genEmit(p, it)
|
||||
of wBreakpoint: genBreakPoint(p, it)
|
||||
of wWatchpoint: genWatchpoint(p, it)
|
||||
else: nil
|
||||
of wWatchPoint: genWatchpoint(p, it)
|
||||
of wInjectStmt:
|
||||
var p = newProc(nil, p.module)
|
||||
p.options = p.options - {optLineTrace, optStackTrace}
|
||||
genStmts(p, it.sons[1])
|
||||
p.module.injectStmt = p.s(cpsStmts)
|
||||
else: discard
|
||||
|
||||
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
|
||||
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
|
||||
if optFieldCheck in p.options:
|
||||
var le = asgn.sons[0]
|
||||
if le.kind == nkCheckedFieldExpr:
|
||||
@@ -840,7 +969,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
assert t.kind == tyObject
|
||||
discard genTypeInfo(p.module, t)
|
||||
var L = lengthOrd(field.typ)
|
||||
if not ContainsOrIncl(p.module.declaredThings, field.id):
|
||||
if not containsOrIncl(p.module.declaredThings, field.id):
|
||||
appcg(p.module, cfsVars, "extern $1",
|
||||
discriminatorTableDecl(p.module, t, field))
|
||||
lineCg(p, cpsStmts,
|
||||
@@ -853,7 +982,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
var dotExpr = e.sons[0]
|
||||
var d: PSym
|
||||
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
|
||||
InitLocExpr(p, e.sons[0], a)
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
getTemp(p, a.t, tmp)
|
||||
expr(p, e.sons[1], tmp)
|
||||
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
|
||||
@@ -861,9 +990,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
|
||||
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
genLineDir(p, e)
|
||||
if not FieldDiscriminantCheckNeeded(p, e):
|
||||
if not fieldDiscriminantCheckNeeded(p, e):
|
||||
var a: TLoc
|
||||
InitLocExpr(p, e.sons[0], a)
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
assert(a.t != nil)
|
||||
loadInto(p, e.sons[0], e.sons[1], a)
|
||||
@@ -873,4 +1002,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
proc genStmts(p: BProc, t: PNode) =
|
||||
var a: TLoc
|
||||
expr(p, t, a)
|
||||
InternalAssert a.k in {locNone, locTemp}
|
||||
internalAssert a.k in {locNone, locTemp, locLocalVar}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
|
||||
# included from cgen.nim
|
||||
|
||||
proc emulatedThreadVars(): bool {.inline.} =
|
||||
proc emulatedThreadVars(): bool =
|
||||
result = {optThreads, optTlsEmulation} <= gGlobalOptions
|
||||
|
||||
proc AccessThreadLocalVar(p: BProc, s: PSym) =
|
||||
if emulatedThreadVars() and not p.ThreadVarAccessed:
|
||||
p.ThreadVarAccessed = true
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym) =
|
||||
if emulatedThreadVars() and not p.threadVarAccessed:
|
||||
p.threadVarAccessed = true
|
||||
p.module.usesThreadVars = true
|
||||
appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
|
||||
app(p.procSec(cpsInit),
|
||||
@@ -55,7 +55,7 @@ proc generateThreadLocalStorage(m: BModule) =
|
||||
for t in items(nimtvDeps): discard getTypeDesc(m, t)
|
||||
appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
|
||||
|
||||
proc GenerateThreadVarsSize(m: BModule) =
|
||||
proc generateThreadVarsSize(m: BModule) =
|
||||
if nimtv != nil:
|
||||
app(m.s[cfsProcs],
|
||||
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)
|
||||
|
||||
@@ -28,7 +28,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
genTraverseProc(c, accessor, n.sons[i])
|
||||
of nkRecCase:
|
||||
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
|
||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
|
||||
var p = c.p
|
||||
let disc = n.sons[0].sym
|
||||
lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
|
||||
@@ -74,7 +74,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
genTraverseProc(c, accessor.parentObj, typ.sons[i])
|
||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
||||
of tyTuple:
|
||||
let typ = GetUniqueType(typ)
|
||||
let typ = getUniqueType(typ)
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
|
||||
of tyRef, tyString, tySequence:
|
||||
@@ -83,7 +83,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
if typ.callConv == ccClosure:
|
||||
lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClEnv", accessor))
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
var p = c.p
|
||||
@@ -111,7 +111,7 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
|
||||
lineF(p, cpsInit, "a = ($1)p;$n", t)
|
||||
|
||||
c.p = p
|
||||
assert typ.kind != tyTypedesc
|
||||
assert typ.kind != tyTypeDesc
|
||||
if typ.kind == tySequence:
|
||||
genTraverseProcSeq(c, "a".toRope, typ)
|
||||
else:
|
||||
@@ -127,18 +127,22 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
|
||||
m.s[cfsProcHeaders].appf("$1;$n", header)
|
||||
m.s[cfsProcs].app(generatedProc)
|
||||
|
||||
|
||||
proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
|
||||
discard genTypeInfo(m, s.loc.t)
|
||||
|
||||
var c: TTraversalClosure
|
||||
var p = newProc(nil, m)
|
||||
var sLoc = s.loc.r
|
||||
result = getGlobalTempName()
|
||||
|
||||
if sfThread in s.flags and emulatedThreadVars():
|
||||
accessThreadLocalVar(p, s)
|
||||
sLoc = con("NimTV->", sLoc)
|
||||
|
||||
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
||||
c.p = p
|
||||
let header = ropef("N_NIMCALL(void, $1)()", result)
|
||||
genTraverseProc(c, s.loc.r, s.loc.t)
|
||||
genTraverseProc(c, sLoc, s.loc.t)
|
||||
|
||||
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
|
||||
@@ -25,7 +25,7 @@ proc mangleField(name: string): string =
|
||||
of 'A'..'Z':
|
||||
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
|
||||
of '_':
|
||||
nil
|
||||
discard
|
||||
of 'a'..'z', '0'..'9':
|
||||
add(result, name[i])
|
||||
else:
|
||||
@@ -48,7 +48,7 @@ proc mangle(name: string): string =
|
||||
of 'A'..'Z':
|
||||
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
|
||||
of '_':
|
||||
nil
|
||||
discard
|
||||
of 'a'..'z', '0'..'9':
|
||||
add(result, name[i])
|
||||
else:
|
||||
@@ -69,17 +69,17 @@ proc mangleName(s: PSym): PRope =
|
||||
if result == nil:
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
case s.kind
|
||||
of skProc, skMethod, skConverter, skConst, skIterator:
|
||||
of skProc, skMethod, skConverter, skConst, skIterators:
|
||||
result = ~"@"
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in s.flags: result = ~"@"
|
||||
else: result = ~"%"
|
||||
of skTemp, skParam, skType, skEnumField, skModule:
|
||||
result = ~"%"
|
||||
else: InternalError(s.info, "mangleName")
|
||||
else: internalError(s.info, "mangleName")
|
||||
when oKeepVariableNames:
|
||||
let keepOrigName = s.kind in skLocalVars - {skForVar} and
|
||||
{sfFromGeneric, sfGlobal, sfShadowed} * s.flags == {} and
|
||||
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
|
||||
not isKeyword(s.name)
|
||||
# XXX: This is still very experimental
|
||||
#
|
||||
@@ -150,7 +150,7 @@ proc getTypeName(typ: PType): PRope =
|
||||
typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope)
|
||||
else: con([~"%", typ.typeName, typ.id.toRope])
|
||||
result = typ.loc.r
|
||||
if result == nil: InternalError("getTypeName: " & $typ.kind)
|
||||
if result == nil: internalError("getTypeName: " & $typ.kind)
|
||||
|
||||
proc mapSetType(typ: PType): TCTypeKind =
|
||||
case int(getSize(typ))
|
||||
@@ -183,9 +183,9 @@ proc mapType(typ: PType): TCTypeKind =
|
||||
else: internalError("mapType")
|
||||
of tyRange: result = mapType(typ.sons[0])
|
||||
of tyPtr, tyVar, tyRef:
|
||||
var base = skipTypes(typ.sons[0], typedescInst)
|
||||
var base = skipTypes(typ.lastSon, typedescInst)
|
||||
case base.kind
|
||||
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
|
||||
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray
|
||||
else: result = ctPtr
|
||||
of tyPointer: result = ctPtr
|
||||
of tySequence: result = ctNimSeq
|
||||
@@ -194,7 +194,7 @@ proc mapType(typ: PType): TCTypeKind =
|
||||
of tyCString: result = ctCString
|
||||
of tyInt..tyUInt64:
|
||||
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
|
||||
else: InternalError("mapType")
|
||||
else: internalError("mapType")
|
||||
|
||||
proc mapReturnType(typ: PType): TCTypeKind =
|
||||
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||
@@ -229,11 +229,11 @@ const
|
||||
"stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline",
|
||||
"$1 noinline", "fastcc $1", "ccc $1", "$1"]
|
||||
|
||||
proc CacheGetType(tab: TIdTable, key: PType): PRope =
|
||||
proc cacheGetType(tab: TIdTable, key: PType): PRope =
|
||||
# returns nil if we need to declare this type
|
||||
# since types are now unique via the ``GetUniqueType`` mechanism, this slow
|
||||
# linear search is not necessary anymore:
|
||||
result = PRope(IdTableGet(tab, key))
|
||||
result = PRope(idTableGet(tab, key))
|
||||
|
||||
proc getTempName(): PRope =
|
||||
result = rfmt(nil, "TMP$1", toRope(backendId()))
|
||||
@@ -246,7 +246,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
|
||||
assert skResult != s.kind
|
||||
if tfByRef in pt.flags: return true
|
||||
elif tfByCopy in pt.flags: return false
|
||||
case pt.Kind
|
||||
case pt.kind
|
||||
of tyObject:
|
||||
if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2):
|
||||
result = true # requested anyway
|
||||
@@ -262,14 +262,14 @@ proc ccgIntroducedPtr(s: PSym): bool =
|
||||
proc fillResult(param: PSym) =
|
||||
fillLoc(param.loc, locParam, param.typ, ~"Result",
|
||||
OnStack)
|
||||
if (mapReturnType(param.typ) != ctArray) and IsInvalidReturnType(param.typ):
|
||||
if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
|
||||
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
|
||||
when false:
|
||||
if t.Kind in {tyRef, tyPtr, tyVar}:
|
||||
var b = skipTypes(t.sons[0], typedescInst)
|
||||
var b = skipTypes(t.lastson, typedescInst)
|
||||
if b.kind == tySet and mapSetType(b) == ctArray:
|
||||
return getTypeDescAux(m, b, check)
|
||||
result = getTypeDescAux(m, t, check)
|
||||
@@ -288,7 +288,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t.sons[0], check)
|
||||
for i in countup(1, sonsLen(t.n) - 1):
|
||||
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
|
||||
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
|
||||
var param = t.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
if params != nil: app(params, ~", ")
|
||||
@@ -305,7 +305,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
var arr = param.typ
|
||||
if arr.kind == tyVar: arr = arr.sons[0]
|
||||
var j = 0
|
||||
while arr.Kind in {tyOpenArray, tyVarargs}:
|
||||
while arr.kind in {tyOpenArray, tyVarargs}:
|
||||
# this fixes the 'sort' bug:
|
||||
if param.typ.kind == tyVar: param.loc.s = OnUnknown
|
||||
# need to pass hidden parameter:
|
||||
@@ -344,7 +344,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
||||
"NI", "NI8", "NI16", "NI32", "NI64",
|
||||
"NF", "NF32", "NF64", "NF128",
|
||||
"NU", "NU8", "NU16", "NU32", "NU64",]
|
||||
case typ.Kind
|
||||
case typ.kind
|
||||
of tyPointer:
|
||||
result = typeNameOrLiteral(typ, "void*")
|
||||
of tyEnum:
|
||||
@@ -362,12 +362,12 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
||||
of tyString:
|
||||
discard cgsym(m, "NimStringDesc")
|
||||
result = typeNameOrLiteral(typ, "NimStringDesc*")
|
||||
of tyCstring: result = typeNameOrLiteral(typ, "NCSTRING")
|
||||
of tyCString: result = typeNameOrLiteral(typ, "NCSTRING")
|
||||
of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
|
||||
of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
|
||||
of tyNil: result = typeNameOrLiteral(typ, "0")
|
||||
of tyInt..tyUInt64:
|
||||
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind])
|
||||
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
|
||||
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
|
||||
else: result = nil
|
||||
|
||||
@@ -375,14 +375,17 @@ proc getTypePre(m: BModule, typ: PType): PRope =
|
||||
if typ == nil: result = toRope("void")
|
||||
else:
|
||||
result = getSimpleTypeDesc(m, typ)
|
||||
if result == nil: result = CacheGetType(m.typeCache, typ)
|
||||
|
||||
if result == nil: result = cacheGetType(m.typeCache, typ)
|
||||
|
||||
proc structOrUnion(t: PType): PRope =
|
||||
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
||||
|
||||
proc getForwardStructFormat(): string =
|
||||
if gCmd == cmdCompileToCpp: result = "struct $1;$n"
|
||||
else: result = "typedef struct $1 $1;$n"
|
||||
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
|
||||
else: result = "typedef $1 $2 $2;$n"
|
||||
|
||||
proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
result = CacheGetType(m.forwTypeCache, typ)
|
||||
result = cacheGetType(m.forwTypeCache, typ)
|
||||
if result != nil: return
|
||||
result = getTypePre(m, typ)
|
||||
if result != nil: return
|
||||
@@ -390,9 +393,10 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
of tySequence, tyTuple, tyObject:
|
||||
result = getTypeName(typ)
|
||||
if not isImportedType(typ):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
||||
IdTablePut(m.forwTypeCache, typ, result)
|
||||
else: InternalError("getTypeForward(" & $typ.kind & ')')
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
[structOrUnion(typ), result])
|
||||
idTablePut(m.forwTypeCache, typ, result)
|
||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||
|
||||
proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
|
||||
if (rectype.sym != nil) and
|
||||
@@ -400,7 +404,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
|
||||
result = field.loc.r
|
||||
else:
|
||||
result = toRope(mangleField(field.name.s))
|
||||
if result == nil: InternalError(field.info, "mangleRecFieldName")
|
||||
if result == nil: internalError(field.info, "mangleRecFieldName")
|
||||
|
||||
proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
accessExpr: PRope, rectype: PType,
|
||||
@@ -415,7 +419,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
|
||||
of nkRecCase:
|
||||
if (n.sons[0].kind != nkSym): InternalError(n.info, "genRecordFieldsAux")
|
||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genRecordFieldsAux")
|
||||
app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
|
||||
uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
|
||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
|
||||
@@ -437,14 +441,20 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
app(result, genRecordFieldsAux(m, k, ae, rectype, check))
|
||||
else: internalError("genRecordFieldsAux(record case branch)")
|
||||
appf(result, "} $1;$n", [uname])
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
field = n.sym
|
||||
if field.typ.kind == tyEmpty: return
|
||||
#assert(field.ast == nil)
|
||||
sname = mangleRecFieldName(field, rectype)
|
||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||
else: ae = sname
|
||||
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
||||
let fieldType = field.loc.t
|
||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||
else:
|
||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
|
||||
else: internalError(n.info, "genRecordFieldsAux()")
|
||||
|
||||
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
@@ -454,23 +464,33 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var TIntSet): PRope =
|
||||
# declare the record:
|
||||
var hasField = false
|
||||
|
||||
var attribute: PRope =
|
||||
if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma)
|
||||
else: nil
|
||||
|
||||
result = ropecg(m, CC[ccompiler].structStmtFmt,
|
||||
[structOrUnion(typ), name, attribute])
|
||||
|
||||
if typ.kind == tyObject:
|
||||
|
||||
if typ.sons[0] == nil:
|
||||
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
|
||||
result = ropecg(m, "struct $1 {$n", [name])
|
||||
appcg(m, result, " {$n", [])
|
||||
else:
|
||||
result = ropecg(m, "struct $1 {$n#TNimType* m_type;$n", [name])
|
||||
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
|
||||
hasField = true
|
||||
elif gCmd == cmdCompileToCpp:
|
||||
result = ropecg(m, "struct $1 : public $2 {$n",
|
||||
[name, getTypeDescAux(m, typ.sons[0], check)])
|
||||
appcg(m, result, " : public $1 {$n",
|
||||
[getTypeDescAux(m, typ.sons[0], check)])
|
||||
hasField = true
|
||||
else:
|
||||
result = ropecg(m, "struct $1 {$n $2 Sup;$n",
|
||||
[name, getTypeDescAux(m, typ.sons[0], check)])
|
||||
appcg(m, result, " {$n $1 Sup;$n",
|
||||
[getTypeDescAux(m, typ.sons[0], check)])
|
||||
hasField = true
|
||||
else:
|
||||
result = ropef("struct $1 {$n", [name])
|
||||
appf(result, " {$n", [name])
|
||||
|
||||
var desc = getRecordFields(m, typ, check)
|
||||
if (desc == nil) and not hasField:
|
||||
appf(result, "char dummy;$n", [])
|
||||
@@ -479,8 +499,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||
app(result, "};" & tnl)
|
||||
|
||||
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var TIntSet): PRope =
|
||||
result = ropef("struct $1 {$n", [name])
|
||||
check: var TIntSet): PRope =
|
||||
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
||||
var desc: PRope = nil
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
appf(desc, "$1 Field$2;$n",
|
||||
@@ -496,49 +516,49 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
# returns only the type's name
|
||||
var
|
||||
name, rettype, desc, recdesc: PRope
|
||||
n: biggestInt
|
||||
n: BiggestInt
|
||||
t, et: PType
|
||||
t = getUniqueType(typ)
|
||||
if t == nil: InternalError("getTypeDescAux: t == nil")
|
||||
if t == nil: internalError("getTypeDescAux: t == nil")
|
||||
if t.sym != nil: useHeader(m, t.sym)
|
||||
result = getTypePre(m, t)
|
||||
if result != nil: return
|
||||
if ContainsOrIncl(check, t.id):
|
||||
InternalError("cannot generate C type for: " & typeToString(typ))
|
||||
if containsOrIncl(check, t.id):
|
||||
internalError("cannot generate C type for: " & typeToString(typ))
|
||||
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
|
||||
# but determining when this needs to be done is hard. We should split
|
||||
# C type generation into an analysis and a code generation phase somehow.
|
||||
case t.Kind
|
||||
case t.kind
|
||||
of tyRef, tyPtr, tyVar:
|
||||
et = getUniqueType(t.sons[0])
|
||||
et = getUniqueType(t.lastSon)
|
||||
if et.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
|
||||
# this is correct! sets have no proper base type, so we treat
|
||||
# ``var set[char]`` in `getParamTypeDesc`
|
||||
et = getUniqueType(elemType(et))
|
||||
case et.Kind
|
||||
case et.kind
|
||||
of tyObject, tyTuple:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
name = getTypeForward(m, et)
|
||||
result = con(name, "*")
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
pushType(m, et)
|
||||
of tySequence:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
name = getTypeForward(m, et)
|
||||
result = con(name, "**")
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
pushType(m, et)
|
||||
else:
|
||||
# else we have a strong dependency :-(
|
||||
result = con(getTypeDescAux(m, et, check), "*")
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyOpenArray, tyVarargs:
|
||||
et = getUniqueType(t.sons[0])
|
||||
result = con(getTypeDescAux(m, et, check), "*")
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyProc:
|
||||
result = getTypeName(t)
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
genProcParams(m, t, rettype, desc, check)
|
||||
if not isImportedType(t):
|
||||
if t.callConv != ccClosure: # procedure vars may need a closure!
|
||||
@@ -552,14 +572,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
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, t)
|
||||
result = cacheGetType(m.forwTypeCache, t)
|
||||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
||||
IdTablePut(m.forwTypeCache, t, result)
|
||||
assert(CacheGetType(m.typeCache, t) == nil)
|
||||
IdTablePut(m.typeCache, t, con(result, "*"))
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
assert(cacheGetType(m.typeCache, t) == nil)
|
||||
idTablePut(m.typeCache, t, con(result, "*"))
|
||||
if not isImportedType(t):
|
||||
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
|
||||
const
|
||||
@@ -578,18 +599,19 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
if n <= 0:
|
||||
n = 1 # make an array of at least one element
|
||||
result = getTypeName(t)
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
|
||||
[getTypeDescAux(m, t.sons[1], check), result, ToRope(n)])
|
||||
[getTypeDescAux(m, t.sons[1], check), result, toRope(n)])
|
||||
of tyObject, tyTuple:
|
||||
result = CacheGetType(m.forwTypeCache, t)
|
||||
result = cacheGetType(m.forwTypeCache, t)
|
||||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
||||
IdTablePut(m.forwTypeCache, t, result)
|
||||
IdTablePut(m.typeCache, t, result) # always call for sideeffects:
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result) # always call for sideeffects:
|
||||
if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
|
||||
else: recdesc = getTupleDesc(m, t, result, check)
|
||||
if not isImportedType(t): app(m.s[cfsTypes], recdesc)
|
||||
@@ -601,7 +623,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
of 8: result = toRope("NU64")
|
||||
else:
|
||||
result = getTypeName(t)
|
||||
IdTablePut(m.typeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
|
||||
[result, toRope(getSize(t))])
|
||||
@@ -609,7 +631,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
tyIter, tyTypeDesc:
|
||||
result = getTypeDescAux(m, lastSon(t), check)
|
||||
else:
|
||||
InternalError("getTypeDescAux(" & $t.kind & ')')
|
||||
internalError("getTypeDescAux(" & $t.kind & ')')
|
||||
result = nil
|
||||
# fixes bug #145:
|
||||
excl(check, t.id)
|
||||
@@ -651,7 +673,9 @@ proc finishTypeDescriptions(m: BModule) =
|
||||
while i < len(m.typeStack):
|
||||
discard getTypeDesc(m, m.typeStack[i])
|
||||
inc(i)
|
||||
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
|
||||
|
||||
proc genProcHeader(m: BModule, prc: PSym): PRope =
|
||||
var
|
||||
rettype, params: PRope
|
||||
@@ -669,12 +693,16 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
# careful here! don't access ``prc.ast`` as that could reload large parts of
|
||||
# the object graph!
|
||||
appf(result, "$1($2, $3)$4",
|
||||
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r, params])
|
||||
if prc.constraint.isNil:
|
||||
appf(result, "$1($2, $3)$4",
|
||||
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
|
||||
params])
|
||||
else:
|
||||
result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params])
|
||||
|
||||
# ------------------ type info generation -------------------------------------
|
||||
|
||||
proc genTypeInfo(m: BModule, typ: PType): PRope
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope
|
||||
proc getNimNode(m: BModule): PRope =
|
||||
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
|
||||
inc(m.typeNodes)
|
||||
@@ -692,7 +720,7 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||
(typ.sons[0] == nil) or isPureObject(typ))
|
||||
|
||||
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||
var nimtypeKind: int
|
||||
#allocMemTI(m, typ, name)
|
||||
if isObjLackingTypeField(typ):
|
||||
@@ -730,10 +758,10 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
var objtype = objtype
|
||||
while lookupInRecord(objtype.n, d.name) == nil:
|
||||
objtype = objtype.sons[0]
|
||||
if objType.sym == nil:
|
||||
InternalError(d.info, "anonymous obj with discriminator")
|
||||
if objtype.sym == nil:
|
||||
internalError(d.info, "anonymous obj with discriminator")
|
||||
result = ropef("NimDT_$1_$2", [
|
||||
toRope(objType.sym.name.s.mangle), toRope(d.name.s.mangle)])
|
||||
toRope(objtype.sym.name.s.mangle), toRope(d.name.s.mangle)])
|
||||
|
||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
discard cgsym(m, "TNimNode")
|
||||
@@ -901,21 +929,21 @@ type
|
||||
|
||||
include ccgtrav
|
||||
|
||||
proc genTypeInfo(m: BModule, typ: PType): PRope =
|
||||
var t = getUniqueType(typ)
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
var t = getUniqueType(t)
|
||||
result = ropef("NTI$1", [toRope(t.id)])
|
||||
let owner = typ.skipTypes(typedescPtrs).owner.getModule
|
||||
if containsOrIncl(m.typeInfoMarker, t.id):
|
||||
return con("(&".toRope, result, ")".toRope)
|
||||
let owner = t.skipTypes(typedescPtrs).owner.getModule
|
||||
if owner != m.module:
|
||||
# make sure the type info is created in the owner module
|
||||
discard genTypeInfo(owner.bmod, typ)
|
||||
# refenrece the type info as extern here
|
||||
discard genTypeInfo(owner.bmod, t)
|
||||
# reference the type info as extern here
|
||||
discard cgsym(m, "TNimType")
|
||||
discard cgsym(m, "TNimNode")
|
||||
appf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
|
||||
[result, toRope(typeToString(t))])
|
||||
return con("(&".toRope, result, ")".toRope)
|
||||
if ContainsOrIncl(m.typeInfoMarker, t.id):
|
||||
return con("(&".toRope, result, ")".toRope)
|
||||
case t.kind
|
||||
of tyEmpty: result = toRope"0"
|
||||
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
||||
@@ -941,8 +969,8 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
|
||||
# BUGFIX: use consistently RTTI without proper field names; otherwise
|
||||
# results are not deterministic!
|
||||
genTupleInfo(m, t, result)
|
||||
else: InternalError("genTypeInfo(" & $t.kind & ')')
|
||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||
result = con("(&".toRope, result, ")".toRope)
|
||||
|
||||
proc genTypeSection(m: BModule, n: PNode) =
|
||||
nil
|
||||
discard
|
||||
|
||||
@@ -22,19 +22,19 @@ proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
of nkPragma:
|
||||
for i in 0 .. < n.len:
|
||||
if whichPragma(n[i]) == w: return n[i]
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
||||
result = getPragmaStmt(n, w) != nil
|
||||
|
||||
proc hashString*(s: string): biggestInt =
|
||||
proc hashString*(s: string): BiggestInt =
|
||||
# has to be the same algorithm as system.hashString!
|
||||
if CPU[targetCPU].bit == 64:
|
||||
# we have to use the same bitwidth
|
||||
# as the target CPU
|
||||
var b = 0'i64
|
||||
for i in countup(0, len(s) - 1):
|
||||
b = b +% Ord(s[i])
|
||||
b = b +% ord(s[i])
|
||||
b = b +% `shl`(b, 10)
|
||||
b = b xor `shr`(b, 6)
|
||||
b = b +% `shl`(b, 3)
|
||||
@@ -44,7 +44,7 @@ proc hashString*(s: string): biggestInt =
|
||||
else:
|
||||
var a = 0'i32
|
||||
for i in countup(0, len(s) - 1):
|
||||
a = a +% Ord(s[i]).int32
|
||||
a = a +% ord(s[i]).int32
|
||||
a = a +% `shl`(a, 10'i32)
|
||||
a = a xor `shr`(a, 6'i32)
|
||||
a = a +% `shl`(a, 3'i32)
|
||||
@@ -57,7 +57,7 @@ var
|
||||
gCanonicalTypes: array[TTypeKind, PType]
|
||||
|
||||
proc initTypeTables() =
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
|
||||
|
||||
proc resetCaches* =
|
||||
## XXX: fix that more properly
|
||||
@@ -70,7 +70,7 @@ when false:
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)):
|
||||
echo i, " ", gTypeTable[i].counter
|
||||
|
||||
proc GetUniqueType*(key: PType): PType =
|
||||
proc getUniqueType*(key: PType): PType =
|
||||
# this is a hotspot in the compiler!
|
||||
if key == nil: return
|
||||
var k = key.kind
|
||||
@@ -86,12 +86,12 @@ proc GetUniqueType*(key: PType): PType =
|
||||
if result == nil:
|
||||
gCanonicalTypes[k] = key
|
||||
result = key
|
||||
of tyTypeDesc, tyTypeClass:
|
||||
InternalError("value expected, but got a type")
|
||||
of tyGenericParam:
|
||||
InternalError("GetUniqueType")
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
||||
result = GetUniqueType(lastSon(key))
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam,
|
||||
tyFromExpr, tyFieldAccessor:
|
||||
internalError("GetUniqueType")
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
|
||||
tyConst, tyIter, tyStatic:
|
||||
result = getUniqueType(lastSon(key))
|
||||
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
|
||||
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
||||
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
||||
@@ -102,51 +102,50 @@ proc GetUniqueType*(key: PType): PType =
|
||||
|
||||
# we have to do a slow linear search because types may need
|
||||
# to be compared by their structure:
|
||||
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
IdTablePut(gTypeTable[k], key, key)
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
of tyObject:
|
||||
if tfFromGeneric notin key.flags:
|
||||
# fast case; lookup per id suffices:
|
||||
result = PType(IdTableGet(gTypeTable[k], key))
|
||||
result = PType(idTableGet(gTypeTable[k], key))
|
||||
if result == nil:
|
||||
IdTablePut(gTypeTable[k], key, key)
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
else:
|
||||
# ugly slow case: need to compare by structure
|
||||
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameType(t, key):
|
||||
return t
|
||||
IdTablePut(gTypeTable[k], key, key)
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
of tyEnum:
|
||||
result = PType(IdTableGet(gTypeTable[k], key))
|
||||
result = PType(idTableGet(gTypeTable[k], key))
|
||||
if result == nil:
|
||||
IdTablePut(gTypeTable[k], key, key)
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
of tyProc:
|
||||
# tyVar is not 100% correct, but would speeds things up a little:
|
||||
if key.callConv != ccClosure:
|
||||
result = key
|
||||
else:
|
||||
# ugh, we need the canon here:
|
||||
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
IdTablePut(gTypeTable[k], key, key)
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
|
||||
proc TableGetType*(tab: TIdTable, key: PType): PObject =
|
||||
proc tableGetType*(tab: TIdTable, key: PType): PObject =
|
||||
# returns nil if we need to declare this type
|
||||
result = IdTableGet(tab, key)
|
||||
result = idTableGet(tab, key)
|
||||
if (result == nil) and (tab.counter > 0):
|
||||
# we have to do a slow linear search because types may need
|
||||
# to be compared by their structure:
|
||||
@@ -169,7 +168,7 @@ proc makeLLVMString*(s: string): PRope =
|
||||
for i in countup(0, len(s) - 1):
|
||||
if (i + 1) mod MaxLineLength == 0:
|
||||
app(result, toRope(res))
|
||||
setlen(res, 0)
|
||||
setLen(res, 0)
|
||||
case s[i]
|
||||
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
||||
add(res, '\\')
|
||||
@@ -178,4 +177,4 @@ proc makeLLVMString*(s: string): PRope =
|
||||
add(res, "\\00\"")
|
||||
app(result, toRope(res))
|
||||
|
||||
InitTypeTables()
|
||||
initTypeTables()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -14,7 +14,7 @@ import
|
||||
options, intsets,
|
||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases
|
||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings
|
||||
|
||||
when options.hasTinyCBackend:
|
||||
import tccgen
|
||||
@@ -52,7 +52,7 @@ proc emitLazily(s: PSym): bool {.inline.} =
|
||||
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
|
||||
result.k = k
|
||||
result.s = s
|
||||
result.t = GetUniqueType(typ)
|
||||
result.t = getUniqueType(typ)
|
||||
result.r = nil
|
||||
result.a = - 1
|
||||
result.flags = {}
|
||||
@@ -72,10 +72,15 @@ proc isSimpleConst(typ: PType): bool =
|
||||
{tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence} and not
|
||||
(t.kind == tyProc and t.callConv == ccClosure)
|
||||
|
||||
proc useStringh(m: BModule) =
|
||||
if not m.includesStringh:
|
||||
m.includesStringh = true
|
||||
discard lists.includeStr(m.headerFiles, "<string.h>")
|
||||
|
||||
proc useHeader(m: BModule, sym: PSym) =
|
||||
if lfHeader in sym.loc.Flags:
|
||||
if lfHeader in sym.loc.flags:
|
||||
assert(sym.annex != nil)
|
||||
discard lists.IncludeStr(m.headerFiles, getStr(sym.annex.path))
|
||||
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
|
||||
|
||||
proc cgsym(m: BModule, name: string): PRope
|
||||
|
||||
@@ -98,7 +103,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if i >= length or not (frmt[i] in {'0'..'9'}): break
|
||||
num = j
|
||||
@@ -111,7 +116,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
of 'N':
|
||||
app(result, rnl)
|
||||
inc(i)
|
||||
else: InternalError("ropes: invalid format string $" & frmt[i])
|
||||
else: internalError("ropes: invalid format string $" & frmt[i])
|
||||
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
|
||||
inc(i)
|
||||
var j = i
|
||||
@@ -123,7 +128,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
inc(i, 2)
|
||||
var j = 0
|
||||
while frmt[i] in Digits:
|
||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
app(result, cgsym(m, args[j-1].ropeToStr))
|
||||
var start = i
|
||||
@@ -189,7 +194,7 @@ when compileTimeRopeFmt:
|
||||
if i - 1 >= start:
|
||||
yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
|
||||
|
||||
macro rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
|
||||
macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
|
||||
## Experimental optimized rope-formatting operator
|
||||
## The run-time code it produces will be very fast, but will it speed up
|
||||
## the compilation of nimrod itself or will the macro execution time
|
||||
@@ -204,7 +209,7 @@ when compileTimeRopeFmt:
|
||||
of ffParam:
|
||||
result.add(args[frag.intValue])
|
||||
else:
|
||||
template rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
|
||||
ropecg(m, fmt, args)
|
||||
|
||||
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
|
||||
@@ -274,16 +279,22 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
if optEmbedOrigSrc in gGlobalOptions:
|
||||
app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
|
||||
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
|
||||
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
|
||||
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags):
|
||||
linefmt(p, cpsStmts, "#endb($1, $2);$n",
|
||||
line.toRope, makeCString(toFilename(t.info)))
|
||||
elif ({optLineTrace, optStackTrace} * p.Options ==
|
||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||
{optLineTrace, optStackTrace}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags):
|
||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||
line.toRope, t.info.quotedFilename)
|
||||
|
||||
proc postStmtActions(p: BProc) {.inline.} =
|
||||
app(p.s(cpsStmts), p.module.injectStmt)
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(): bool {.inline.}
|
||||
|
||||
include "ccgtypes.nim"
|
||||
|
||||
# ------------------------------ Manager of temporaries ------------------
|
||||
@@ -308,7 +319,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
takeAddr: bool) =
|
||||
case analyseObjectWithTypeField(t)
|
||||
of frNone:
|
||||
nil
|
||||
discard
|
||||
of frHeader:
|
||||
var r = rdLoc(a)
|
||||
if not takeAddr: r = ropef("(*$1)", [r])
|
||||
@@ -340,12 +351,14 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
|
||||
if containsGcRef:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.t, onStack)
|
||||
initLoc(nilLoc, locTemp, loc.t, OnStack)
|
||||
nilLoc.r = toRope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
|
||||
else:
|
||||
if optNilCheck in p.options:
|
||||
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc))
|
||||
if loc.s != OnStack:
|
||||
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
addrLoc(loc), genTypeInfo(p.module, loc.t))
|
||||
@@ -353,19 +366,24 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
# field, so disabling this should be safe:
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, true)
|
||||
else:
|
||||
useStringh(p.module)
|
||||
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
|
||||
addrLoc(loc), rdLoc(loc))
|
||||
# XXX: We can be extra clever here and call memset only
|
||||
# on the bytes following the m_type field?
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, true)
|
||||
|
||||
proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) =
|
||||
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
|
||||
if not isComplexValueType(skipTypes(loc.t, abstractRange)):
|
||||
linefmt(p, section, "$1 = 0;$n", rdLoc(loc))
|
||||
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
|
||||
else:
|
||||
linefmt(p, section, "memset((void*)$1, 0, sizeof($2));$n",
|
||||
addrLoc(loc), rdLoc(loc))
|
||||
genObjectInit(p, section, loc.t, loc, true)
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use memset for temporary values for performance if we can
|
||||
# avoid it:
|
||||
useStringh(p.module)
|
||||
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
|
||||
addrLoc(loc), rdLoc(loc))
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, true)
|
||||
|
||||
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
if sfNoInit notin v.flags:
|
||||
@@ -379,12 +397,6 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
if not immediateAsgn:
|
||||
constructLoc(p, v.loc)
|
||||
|
||||
proc initTemp(p: BProc, tmp: var TLoc) =
|
||||
# XXX: This is still suspicious.
|
||||
# Objects should always be constructed?
|
||||
if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t):
|
||||
constructLoc(p, tmp)
|
||||
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc) =
|
||||
inc(p.labels)
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
@@ -397,7 +409,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
|
||||
result.t = getUniqueType(t)
|
||||
result.s = OnStack
|
||||
result.flags = {}
|
||||
initTemp(p, result)
|
||||
constructLoc(p, result, isTemp=true)
|
||||
|
||||
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||
when false:
|
||||
@@ -419,6 +431,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||
if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)):
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(result), rdLoc(toKeepAlive))
|
||||
else:
|
||||
useStringh(p.module)
|
||||
linefmt(p, cpsStmts,
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||
addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
|
||||
@@ -486,18 +499,21 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
|
||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
var decl = getTypeDesc(p.module, s.loc.t)
|
||||
if sfRegister in s.flags: app(decl, " register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# app(decl, " GC_GUARD")
|
||||
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
|
||||
app(decl, " volatile")
|
||||
appf(decl, " $1;$n", [s.loc.r])
|
||||
if s.constraint.isNil:
|
||||
if sfRegister in s.flags: app(decl, " register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# app(decl, " GC_GUARD")
|
||||
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
|
||||
app(decl, " volatile")
|
||||
appf(decl, " $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
|
||||
line(p, cpsLocals, decl)
|
||||
localDebugInfo(p, s)
|
||||
|
||||
include ccgthreadvars
|
||||
|
||||
proc VarInDynamicLib(m: BModule, sym: PSym)
|
||||
proc varInDynamicLib(m: BModule, sym: PSym)
|
||||
proc mangleDynLibProc(sym: PSym): PRope
|
||||
|
||||
proc assignGlobalVar(p: BProc, s: PSym) =
|
||||
@@ -506,8 +522,8 @@ proc assignGlobalVar(p: BProc, s: PSym) =
|
||||
|
||||
if lfDynamicLib in s.loc.flags:
|
||||
var q = findPendingModule(p.module, s)
|
||||
if q != nil and not ContainsOrIncl(q.declaredThings, s.id):
|
||||
VarInDynamicLib(q, s)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, s.id):
|
||||
varInDynamicLib(q, s)
|
||||
else:
|
||||
s.loc.r = mangleDynLibProc(s)
|
||||
return
|
||||
@@ -516,11 +532,17 @@ proc assignGlobalVar(p: BProc, s: PSym) =
|
||||
if sfThread in s.flags:
|
||||
declareThreadVar(p.module, s, sfImportc in s.flags)
|
||||
else:
|
||||
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
|
||||
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
|
||||
if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
|
||||
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
|
||||
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
|
||||
var decl: PRope = nil
|
||||
var td = getTypeDesc(p.module, s.loc.t)
|
||||
if s.constraint.isNil:
|
||||
if sfImportc in s.flags: app(decl, "extern ")
|
||||
app(decl, td)
|
||||
if sfRegister in s.flags: app(decl, " register")
|
||||
if sfVolatile in s.flags: app(decl, " volatile")
|
||||
appf(decl, " $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r)
|
||||
app(p.module.s[cfsVars], decl)
|
||||
if p.withinLoop > 0:
|
||||
# fixes tests/run/tzeroarray:
|
||||
resetLoc(p, s.loc)
|
||||
@@ -556,7 +578,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
proc genProcPrototype(m: BModule, sym: PSym)
|
||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
||||
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
||||
proc intLiteral(i: biggestInt): PRope
|
||||
proc intLiteral(i: BiggestInt): PRope
|
||||
proc genLiteral(p: BProc, n: PNode): PRope
|
||||
|
||||
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
||||
@@ -588,7 +610,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
var s: TStringSeq = @[]
|
||||
libCandidates(lib.path.strVal, s)
|
||||
if gVerbosity >= 2:
|
||||
MsgWriteln("Dependency: " & lib.path.strVal)
|
||||
msgWriteln("Dependency: " & lib.path.strVal)
|
||||
var loadlib: PRope = nil
|
||||
for i in countup(0, high(s)):
|
||||
inc(m.labels)
|
||||
@@ -610,7 +632,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
|
||||
[tmp, rdLoc(dest)])
|
||||
|
||||
if lib.name == nil: InternalError("loadDynamicLib")
|
||||
if lib.name == nil: internalError("loadDynamicLib")
|
||||
|
||||
proc mangleDynLibProc(sym: PSym): PRope =
|
||||
if sfCompilerProc in sym.flags:
|
||||
@@ -619,7 +641,7 @@ proc mangleDynLibProc(sym: PSym): PRope =
|
||||
else:
|
||||
result = ropef("Dl_$1", [toRope(sym.id)])
|
||||
|
||||
proc SymInDynamicLib(m: BModule, sym: PSym) =
|
||||
proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
let isCall = isGetProcAddr(lib)
|
||||
var extname = sym.loc.r
|
||||
@@ -643,14 +665,14 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
|
||||
params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last.sons[1]
|
||||
InternalAssert(last.kind == nkStrLit)
|
||||
internalAssert(last.kind == nkStrLit)
|
||||
let idx = last.strVal
|
||||
if idx.len == 0:
|
||||
app(m.initProc.s(cpsStmts), load)
|
||||
elif idx.len == 1 and idx[0] in {'0'..'9'}:
|
||||
app(m.extensionLoaders[idx[0]], load)
|
||||
else:
|
||||
InternalError(sym.info, "wrong index: " & idx)
|
||||
internalError(sym.info, "wrong index: " & idx)
|
||||
else:
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||
@@ -660,7 +682,7 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
|
||||
"$1 = linkonce global $2 zeroinitializer$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
|
||||
proc VarInDynamicLib(m: BModule, sym: PSym) =
|
||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
var extname = sym.loc.r
|
||||
loadDynamicLib(m, lib)
|
||||
@@ -675,7 +697,7 @@ proc VarInDynamicLib(m: BModule, sym: PSym) =
|
||||
appf(m.s[cfsVars], "$2* $1;$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
|
||||
proc SymInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||
sym.loc.r = mangleDynLibProc(sym)
|
||||
sym.typ.sym = nil # generate a new name
|
||||
|
||||
@@ -683,10 +705,10 @@ proc cgsym(m: BModule, name: string): PRope =
|
||||
var sym = magicsys.getCompilerProc(name)
|
||||
if sym != nil:
|
||||
case sym.kind
|
||||
of skProc, skMethod, skConverter, skIterator: genProc(m, sym)
|
||||
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
|
||||
of skVar, skResult, skLet: genVarPrototype(m, sym)
|
||||
of skType: discard getTypeDesc(m, sym.typ)
|
||||
else: InternalError("cgsym: " & name)
|
||||
else: internalError("cgsym: " & name)
|
||||
else:
|
||||
# we used to exclude the system module from this check, but for DLL
|
||||
# generation support this sloppyness leads to hard to detect bugs, so
|
||||
@@ -702,13 +724,13 @@ proc generateHeaders(m: BModule) =
|
||||
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
|
||||
else:
|
||||
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
|
||||
it = PStrEntry(it.Next)
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc retIsNotVoid(s: PSym): bool =
|
||||
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
|
||||
|
||||
proc initFrame(p: BProc, procname, filename: PRope): PRope =
|
||||
discard cgsym(p.module, "pushFrame")
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
if p.maxFrameLen > 0:
|
||||
discard cgsym(p.module, "TVarSlot")
|
||||
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
|
||||
@@ -725,7 +747,7 @@ proc closureSetup(p: BProc, prc: PSym) =
|
||||
# prc.ast[paramsPos].last contains the type we're after:
|
||||
var ls = lastSon(prc.ast[paramsPos])
|
||||
if ls.kind != nkSym:
|
||||
InternalError(prc.info, "closure generation failed")
|
||||
internalError(prc.info, "closure generation failed")
|
||||
var env = ls.sym
|
||||
#echo "created environment: ", env.id, " for ", prc.name.s
|
||||
assignLocalVar(p, env)
|
||||
@@ -739,6 +761,8 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
var returnStmt: PRope = nil
|
||||
assert(prc.ast != nil)
|
||||
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
internalError(prc.info, "proc has no result symbol")
|
||||
var res = prc.ast.sons[resultPos].sym # get result symbol
|
||||
if not isInvalidReturnType(prc.typ.sons[0]):
|
||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||
@@ -753,6 +777,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
||||
incl(res.loc.flags, lfIndirect)
|
||||
res.loc.s = OnUnknown
|
||||
|
||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
||||
var param = prc.typ.n.sons[i].sym
|
||||
if param.typ.isCompileTimeOnly: continue
|
||||
@@ -760,7 +785,9 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
closureSetup(p, prc)
|
||||
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: PRope
|
||||
if sfPure in prc.flags:
|
||||
if sfPure in prc.flags:
|
||||
if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
|
||||
header = con("__declspec(naked) ", header)
|
||||
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
|
||||
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
|
||||
else:
|
||||
@@ -768,7 +795,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
app(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
app(generatedProc, p.s(cpsLocals))
|
||||
var procname = CStringLit(p, generatedProc, prc.name.s)
|
||||
var procname = cstringLit(p, generatedProc, prc.name.s)
|
||||
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
|
||||
else:
|
||||
app(generatedProc, p.s(cpsLocals))
|
||||
@@ -786,15 +813,18 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
if lfNoDecl in sym.loc.Flags: return
|
||||
if lfDynamicLib in sym.loc.Flags:
|
||||
if lfNoDecl in sym.loc.flags: return
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if getModule(sym).id != m.module.id and
|
||||
not ContainsOrIncl(m.declaredThings, sym.id):
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
|
||||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
|
||||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||
elif not ContainsOrIncl(m.declaredProtos, sym.id):
|
||||
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", genProcHeader(m, sym)))
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
var header = genProcHeader(m, sym)
|
||||
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
|
||||
header.app(" __attribute__((naked))")
|
||||
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
fillProcLoc(prc)
|
||||
@@ -804,21 +834,21 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
discard cgsym(m, prc.name.s)
|
||||
return
|
||||
genProcPrototype(m, prc)
|
||||
if lfNoDecl in prc.loc.Flags: nil
|
||||
if lfNoDecl in prc.loc.flags: discard
|
||||
elif prc.typ.callConv == ccInline:
|
||||
# We add inline procs to the calling module to enable C based inlining.
|
||||
# This also means that a check with ``q.declaredThings`` is wrong, we need
|
||||
# a check for ``m.declaredThings``.
|
||||
if not ContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
|
||||
if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
if q != nil and not ContainsOrIncl(q.declaredThings, prc.id):
|
||||
SymInDynamicLib(q, prc)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
symInDynamicLib(q, prc)
|
||||
else:
|
||||
SymInDynamicLibPartial(m, prc)
|
||||
symInDynamicLibPartial(m, prc)
|
||||
elif sfImportc notin prc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
if q != nil and not ContainsOrIncl(q.declaredThings, prc.id):
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
genProcAux(q, prc)
|
||||
|
||||
proc requestConstImpl(p: BProc, sym: PSym) =
|
||||
@@ -826,15 +856,15 @@ proc requestConstImpl(p: BProc, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
if sym.loc.k == locNone:
|
||||
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
|
||||
if lfNoDecl in sym.loc.Flags: return
|
||||
if lfNoDecl in sym.loc.flags: return
|
||||
# declare implementation:
|
||||
var q = findPendingModule(m, sym)
|
||||
if q != nil and not ContainsOrIncl(q.declaredThings, sym.id):
|
||||
if q != nil and not containsOrIncl(q.declaredThings, sym.id):
|
||||
assert q.initProc.module == q
|
||||
appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
|
||||
# declare header:
|
||||
if q != m and not ContainsOrIncl(m.declaredThings, sym.id):
|
||||
if q != m and not containsOrIncl(m.declaredThings, sym.id):
|
||||
assert(sym.loc.r != nil)
|
||||
let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
|
||||
[getTypeDesc(m, sym.loc.t), sym.loc.r])
|
||||
@@ -847,21 +877,21 @@ proc isActivated(prc: PSym): bool = prc.typ != nil
|
||||
proc genProc(m: BModule, prc: PSym) =
|
||||
if sfBorrow in prc.flags or not isActivated(prc): return
|
||||
fillProcLoc(prc)
|
||||
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
|
||||
else:
|
||||
if sfForward in prc.flags: addForwardedProc(m, prc)
|
||||
else:
|
||||
genProcNoForward(m, prc)
|
||||
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
||||
generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
|
||||
generatedHeader != nil and lfNoDecl notin prc.loc.flags:
|
||||
genProcPrototype(generatedHeader, prc)
|
||||
if prc.typ.callConv == ccInline:
|
||||
if not ContainsOrIncl(generatedHeader.declaredThings, prc.id):
|
||||
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
|
||||
genProcAux(generatedHeader, prc)
|
||||
|
||||
proc genVarPrototypeAux(m: BModule, sym: PSym) =
|
||||
assert(sfGlobal in sym.flags)
|
||||
useHeader(m, sym)
|
||||
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
|
||||
if (lfNoDecl in sym.loc.Flags) or ContainsOrIncl(m.declaredThings, sym.id):
|
||||
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
|
||||
return
|
||||
if sym.owner.id != m.module.id:
|
||||
# else we already have the symbol generated!
|
||||
@@ -883,29 +913,29 @@ proc addIntTypes(result: var PRope) {.inline.} =
|
||||
appf(result, "#define NIM_INTBITS $1", [
|
||||
platform.CPU[targetCPU].intSize.toRope])
|
||||
|
||||
proc getCopyright(cfilenoext: string): PRope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n" &
|
||||
"/* The generated code is subject to the original license. */$n",
|
||||
"; Generated by Nimrod Compiler v$1$n" &
|
||||
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
|
||||
else:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n" &
|
||||
"/* The generated code is subject to the original license. */$n" &
|
||||
"/* Compiled for: $2, $3, $4 */$n" &
|
||||
"/* Command for C compiler:$n $5 */$n",
|
||||
"; Generated by Nimrod Compiler v$1$n" &
|
||||
"; (c) 2012 Andreas Rumpf$n" &
|
||||
"; Compiled for: $2, $3, $4$n" &
|
||||
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.ccompiler].name),
|
||||
proc getCopyright(cfilenoext: string): PRope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
||||
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N",
|
||||
"; Generated by Nimrod Compiler v$1$N" &
|
||||
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
|
||||
else:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
||||
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N" &
|
||||
"/* Compiled for: $2, $3, $4 */$N" &
|
||||
"/* Command for C compiler:$n $5 */$N",
|
||||
"; Generated by Nimrod Compiler v$1$N" &
|
||||
"; (c) 2014 Andreas Rumpf$N" &
|
||||
"; Compiled for: $2, $3, $4$N" &
|
||||
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.cCompiler].name),
|
||||
toRope(getCompileCFileCmd(cfilenoext))])
|
||||
|
||||
proc getFileHeader(cfilenoext: string): PRope =
|
||||
proc getFileHeader(cfilenoext: string): PRope =
|
||||
result = getCopyright(cfilenoext)
|
||||
addIntTypes(result)
|
||||
|
||||
@@ -913,46 +943,72 @@ proc genFilenames(m: BModule): PRope =
|
||||
discard cgsym(m, "dbgRegisterFilename")
|
||||
result = nil
|
||||
for i in 0.. <fileInfos.len:
|
||||
result.appf("dbgRegisterFilename($1);$n", fileInfos[i].projPath.makeCString)
|
||||
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
proc genMainProc(m: BModule) =
|
||||
const
|
||||
CommonMainBody =
|
||||
"\tsystemDatInit();$n" &
|
||||
PreMainBody =
|
||||
"\tsystemDatInit();$N" &
|
||||
"\tsystemInit();$N" &
|
||||
"$1" &
|
||||
"$2" &
|
||||
"$3" &
|
||||
"$4"
|
||||
|
||||
MainProcs =
|
||||
"\tNimMain();$N"
|
||||
|
||||
MainProcsWithResult =
|
||||
MainProcs & "\treturn nim_program_result;$N"
|
||||
|
||||
NimMainBody =
|
||||
"N_CDECL(void, NimMain)(void) {$N" &
|
||||
"\tPreMain();$N" &
|
||||
"$1" &
|
||||
"$2" &
|
||||
"\tsystemInit();$n" &
|
||||
"$3" &
|
||||
"$4"
|
||||
PosixNimMain =
|
||||
"int cmdCount;$n" &
|
||||
"char** cmdLine;$n" &
|
||||
"char** gEnv;$n" &
|
||||
"N_CDECL(void, NimMain)(void) {$n" &
|
||||
CommonMainBody & "}$n"
|
||||
PosixCMain = "int main(int argc, char** args, char** env) {$n" &
|
||||
"\tcmdLine = args;$n" & "\tcmdCount = argc;$n" & "\tgEnv = env;$n" &
|
||||
"\tNimMain();$n" & "\treturn nim_program_result;$n" & "}$n"
|
||||
StandaloneCMain = "int main(void) {$n" &
|
||||
"\tNimMain();$n" &
|
||||
"\treturn 0;$n" & "}$n"
|
||||
WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
|
||||
CommonMainBody & "}$n"
|
||||
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
|
||||
" HINSTANCE hPrevInstance, $n" &
|
||||
" LPSTR lpCmdLine, int nCmdShow) {$n" &
|
||||
"\tNimMain();$n" & "\treturn nim_program_result;$n" & "}$n"
|
||||
WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" &
|
||||
CommonMainBody & "}$n"
|
||||
WinCDllMain =
|
||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
|
||||
" LPVOID lpvReserved) {$n" &
|
||||
"\tif(fwdreason == DLL_PROCESS_ATTACH) NimMain();$n" &
|
||||
"\treturn 1;$n" & "}$n"
|
||||
"}$N$N"
|
||||
|
||||
PosixNimMain =
|
||||
"int cmdCount;$N" &
|
||||
"char** cmdLine;$N" &
|
||||
"char** gEnv;$N" &
|
||||
NimMainBody
|
||||
|
||||
PosixCMain =
|
||||
"int main(int argc, char** args, char** env) {$N" &
|
||||
"\tcmdLine = args;$N" &
|
||||
"\tcmdCount = argc;$N" &
|
||||
"\tgEnv = env;$N" &
|
||||
MainProcsWithResult &
|
||||
"}$N$N"
|
||||
|
||||
StandaloneCMain =
|
||||
"int main(void) {$N" &
|
||||
MainProcs &
|
||||
"\treturn 0;$N" &
|
||||
"}$N$N"
|
||||
|
||||
WinNimMain = NimMainBody
|
||||
|
||||
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
|
||||
" HINSTANCE hPrevInstance, $N" &
|
||||
" LPSTR lpCmdLine, int nCmdShow) {$N" &
|
||||
MainProcsWithResult & "}$N$N"
|
||||
|
||||
WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
|
||||
|
||||
WinCDllMain =
|
||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
|
||||
" LPVOID lpvReserved) {$N" &
|
||||
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
|
||||
"\treturn 1;$N}$N$N"
|
||||
|
||||
PosixNimDllMain = WinNimDllMain
|
||||
PosixCDllMain =
|
||||
"void NIM_POSIX_INIT NimMainInit(void) {$n" &
|
||||
"\tNimMain();$n}$n"
|
||||
|
||||
PosixCDllMain =
|
||||
"void NIM_POSIX_INIT NimMainInit(void) {$N" &
|
||||
MainProcs &
|
||||
"}$N$N"
|
||||
|
||||
var nimMain, otherMain: TFormatStr
|
||||
if platform.targetOS == osWindows and
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
@@ -962,10 +1018,10 @@ proc genMainProc(m: BModule) =
|
||||
else:
|
||||
nimMain = WinNimDllMain
|
||||
otherMain = WinCDllMain
|
||||
discard lists.IncludeStr(m.headerFiles, "<windows.h>")
|
||||
discard lists.includeStr(m.headerFiles, "<windows.h>")
|
||||
elif optGenDynLib in gGlobalOptions:
|
||||
nimMain = posixNimDllMain
|
||||
otherMain = posixCDllMain
|
||||
nimMain = PosixNimDllMain
|
||||
otherMain = PosixCDllMain
|
||||
elif platform.targetOS == osStandalone:
|
||||
nimMain = PosixNimMain
|
||||
otherMain = StandaloneCMain
|
||||
@@ -978,18 +1034,25 @@ proc genMainProc(m: BModule) =
|
||||
|
||||
let initStackBottomCall = if emulatedThreadVars() or
|
||||
platform.targetOS == osStandalone: "".toRope
|
||||
else: ropecg(m, "\t#initStackBottom();$n")
|
||||
else: ropecg(m, "\t#initStackBottom();$N")
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], nimMain, [mainDatInit, initStackBottomCall,
|
||||
gBreakpoints, mainModInit, toRope(m.labels)])
|
||||
appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N$N", [
|
||||
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
|
||||
|
||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
|
||||
if optNoMain notin gGlobalOptions:
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
|
||||
proc getInitName(m: PSym): PRope =
|
||||
result = ropeff("$1Init", "@$1Init", [toRope(m.name.s)])
|
||||
|
||||
proc getDatInitName(m: PSym): PRope =
|
||||
result = ropeff("$1DatInit", "@$1DatInit", [toRope(m.name.s)])
|
||||
proc getSomeInitName(m: PSym, suffix: string): PRope =
|
||||
assert m.kind == skModule
|
||||
assert m.owner.kind == skPackage
|
||||
if {sfSystemModule, sfMainModule} * m.flags == {}:
|
||||
result = m.owner.name.s.mangle.toRope
|
||||
result.app m.name.s
|
||||
result.app suffix
|
||||
|
||||
proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init")
|
||||
proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit")
|
||||
|
||||
proc registerModuleToMain(m: PSym) =
|
||||
var
|
||||
@@ -999,13 +1062,17 @@ proc registerModuleToMain(m: PSym) =
|
||||
"declare void $1() noinline$N", [init])
|
||||
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
||||
"declare void $1() noinline$N", [datInit])
|
||||
if not (sfSystemModule in m.flags):
|
||||
appff(mainModInit, "\t$1();$n", "call void ()* $1$n", [init])
|
||||
appff(mainDatInit, "\t$1();$n", "call void ()* $1$n", [datInit])
|
||||
|
||||
if sfSystemModule notin m.flags:
|
||||
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
|
||||
let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
|
||||
if sfMainModule in m.flags:
|
||||
app(mainModInit, initCall)
|
||||
else:
|
||||
app(otherModsInit, initCall)
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
var initname = getInitName(m.module)
|
||||
var prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
|
||||
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
|
||||
"define void $1() noinline {$n", [initname])
|
||||
if m.typeNodes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||
@@ -1017,35 +1084,38 @@ proc genInitCode(m: BModule) =
|
||||
app(prc, initGCFrame(m.initProc))
|
||||
|
||||
app(prc, genSectionStart(cpsLocals))
|
||||
app(prc, m.initProc.s(cpsLocals))
|
||||
app(prc, m.preInitProc.s(cpsLocals))
|
||||
app(prc, m.initProc.s(cpsLocals))
|
||||
app(prc, m.postInitProc.s(cpsLocals))
|
||||
app(prc, genSectionEnd(cpsLocals))
|
||||
|
||||
if optStackTrace in m.initProc.options and not m.FrameDeclared:
|
||||
if optStackTrace in m.initProc.options and not m.frameDeclared:
|
||||
# BUT: the generated init code might depend on a current frame, so
|
||||
# declare it nevertheless:
|
||||
m.FrameDeclared = true
|
||||
if not m.PreventStackTrace:
|
||||
var procname = CStringLit(m.initProc, prc, m.module.name.s)
|
||||
m.frameDeclared = true
|
||||
if not m.preventStackTrace:
|
||||
var procname = cstringLit(m.initProc, prc, m.module.name.s)
|
||||
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
else:
|
||||
app(prc, ~"\tvolatile TFrame F; F.len = 0;$N")
|
||||
app(prc, ~"\tTFrame F; F.len = 0;$N")
|
||||
|
||||
app(prc, genSectionStart(cpsInit))
|
||||
app(prc, m.preInitProc.s(cpsInit))
|
||||
app(prc, m.initProc.s(cpsInit))
|
||||
app(prc, m.postInitProc.s(cpsInit))
|
||||
app(prc, genSectionEnd(cpsInit))
|
||||
|
||||
app(prc, genSectionStart(cpsStmts))
|
||||
app(prc, m.preInitProc.s(cpsStmts))
|
||||
app(prc, m.initProc.s(cpsStmts))
|
||||
app(prc, m.postInitProc.s(cpsStmts))
|
||||
app(prc, genSectionEnd(cpsStmts))
|
||||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||
if optStackTrace in m.initProc.options and not m.preventStackTrace:
|
||||
app(prc, deinitFrame(m.initProc))
|
||||
app(prc, deinitGCFrame(m.initProc))
|
||||
appf(prc, "}$N$N")
|
||||
|
||||
prc.appff("N_NOINLINE(void, $1)(void) {$n",
|
||||
prc.appff("N_NOINLINE(void, $1)(void) {$N",
|
||||
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
@@ -1083,9 +1153,17 @@ proc newPreInitProc(m: BModule): BProc =
|
||||
# little hack so that unique temporaries are generated:
|
||||
result.labels = 100_000
|
||||
|
||||
proc newPostInitProc(m: BModule): BProc =
|
||||
result = newProc(nil, m)
|
||||
# little hack so that unique temporaries are generated:
|
||||
result.labels = 200_000
|
||||
|
||||
proc initProcOptions(m: BModule): TOptions =
|
||||
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
|
||||
|
||||
proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
new(result)
|
||||
InitLinkedList(result.headerFiles)
|
||||
initLinkedList(result.headerFiles)
|
||||
result.declaredThings = initIntSet()
|
||||
result.declaredProtos = initIntSet()
|
||||
result.cfilename = filename
|
||||
@@ -1095,34 +1173,41 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
result.module = module
|
||||
result.typeInfoMarker = initIntSet()
|
||||
result.initProc = newProc(nil, result)
|
||||
result.initProc.options = gOptions
|
||||
result.initProc.options = initProcOptions(result)
|
||||
result.preInitProc = newPreInitProc(result)
|
||||
result.postInitProc = newPostInitProc(result)
|
||||
initNodeTable(result.dataCache)
|
||||
result.typeStack = @[]
|
||||
result.forwardedProcs = @[]
|
||||
result.typeNodesName = getTempName()
|
||||
result.nimTypesName = getTempName()
|
||||
result.PreventStackTrace = sfSystemModule in module.flags
|
||||
# no line tracing for the init sections of the system module so that we
|
||||
# don't generate a TFrame which can confuse the stack botton initialization:
|
||||
if sfSystemModule in module.flags:
|
||||
result.preventStackTrace = true
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
excl(result.postInitProc.options, optStackTrace)
|
||||
|
||||
proc nullify[T](arr: var T) =
|
||||
for i in low(arr)..high(arr):
|
||||
arr[i] = nil
|
||||
|
||||
proc resetModule*(m: var BModule) =
|
||||
proc resetModule*(m: BModule) =
|
||||
# between two compilations in CAAS mode, we can throw
|
||||
# away all the data that was written to disk
|
||||
InitLinkedList(m.headerFiles)
|
||||
initLinkedList(m.headerFiles)
|
||||
m.declaredProtos = initIntSet()
|
||||
initIdTable(m.forwTypeCache)
|
||||
m.initProc = newProc(nil, m)
|
||||
m.initProc.options = gOptions
|
||||
m.initProc.options = initProcOptions(m)
|
||||
m.preInitProc = newPreInitProc(m)
|
||||
m.postInitProc = newPostInitProc(m)
|
||||
initNodeTable(m.dataCache)
|
||||
m.typeStack = @[]
|
||||
m.forwardedProcs = @[]
|
||||
m.typeNodesName = getTempName()
|
||||
m.nimTypesName = getTempName()
|
||||
m.PreventStackTrace = sfSystemModule in m.module.flags
|
||||
m.preventStackTrace = sfSystemModule in m.module.flags
|
||||
nullify m.s
|
||||
m.usesThreadVars = false
|
||||
m.typeNodes = 0
|
||||
@@ -1149,11 +1234,11 @@ proc resetCgenModules* =
|
||||
for m in cgenModules(): resetModule(m)
|
||||
|
||||
proc rawNewModule(module: PSym): BModule =
|
||||
result = rawNewModule(module, module.filename)
|
||||
result = rawNewModule(module, module.position.int32.toFullPath)
|
||||
|
||||
proc newModule(module: PSym): BModule =
|
||||
# we should create only one cgen module for each module sym
|
||||
InternalAssert getCgenModule(module) == nil
|
||||
internalAssert getCgenModule(module) == nil
|
||||
|
||||
result = rawNewModule(module)
|
||||
growCache gModules, module.position
|
||||
@@ -1161,7 +1246,7 @@ proc newModule(module: PSym): BModule =
|
||||
|
||||
if (optDeadCodeElim in gGlobalOptions):
|
||||
if (sfDeadCodeElim in module.flags):
|
||||
InternalError("added pending module twice: " & module.filename)
|
||||
internalError("added pending module twice: " & module.filename)
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
result = newModule(module)
|
||||
@@ -1192,7 +1277,7 @@ proc writeHeader(m: BModule) =
|
||||
writeRope(result, m.filename)
|
||||
|
||||
proc getCFile(m: BModule): string =
|
||||
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
|
||||
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt)
|
||||
|
||||
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||
assert optSymbolFiles in gGlobalOptions
|
||||
@@ -1204,7 +1289,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil or passes.skipCodegen(n): return
|
||||
var m = BModule(b)
|
||||
m.initProc.options = gOptions
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genStmts(m.initProc, n)
|
||||
|
||||
proc finishModule(m: BModule) =
|
||||
@@ -1214,19 +1299,19 @@ proc finishModule(m: BModule) =
|
||||
# a ``for`` loop here
|
||||
var prc = m.forwardedProcs[i]
|
||||
if sfForward in prc.flags:
|
||||
InternalError(prc.info, "still forwarded: " & prc.name.s)
|
||||
internalError(prc.info, "still forwarded: " & prc.name.s)
|
||||
genProcNoForward(m, prc)
|
||||
inc(i)
|
||||
assert(gForwardedProcsCounter >= i)
|
||||
dec(gForwardedProcsCounter, i)
|
||||
setlen(m.forwardedProcs, 0)
|
||||
setLen(m.forwardedProcs, 0)
|
||||
|
||||
proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool =
|
||||
result = true
|
||||
if optForceFullMake notin gGlobalOptions:
|
||||
var objFile = toObjFile(cfilenoext)
|
||||
if writeRopeIfNotEqual(code, cfile): return
|
||||
if ExistsFile(objFile) and os.FileNewer(objFile, cfile): result = false
|
||||
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
|
||||
else:
|
||||
writeRope(code, cfile)
|
||||
|
||||
@@ -1247,7 +1332,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
if sfMainModule in m.module.flags:
|
||||
# generate main file:
|
||||
app(m.s[cfsProcHeaders], mainModProcs)
|
||||
GenerateThreadVarsSize(m)
|
||||
generateThreadVarsSize(m)
|
||||
|
||||
var code = genModule(m, cfilenoext)
|
||||
when hasTinyCBackend:
|
||||
@@ -1264,7 +1349,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
var code = genModule(m, cfilenoext)
|
||||
writeRope(code, cfile)
|
||||
addFileToCompile(cfilenoext)
|
||||
elif not ExistsFile(toObjFile(cfilenoext)):
|
||||
elif not existsFile(toObjFile(cfilenoext)):
|
||||
# Consider: first compilation compiles ``system.nim`` and produces
|
||||
# ``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:
|
||||
@@ -1291,7 +1376,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||
if b == nil or passes.skipCodegen(n): return
|
||||
var m = BModule(b)
|
||||
if n != nil:
|
||||
m.initProc.options = gOptions
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genStmts(m.initProc, n)
|
||||
# cached modules need to registered too:
|
||||
registerModuleToMain(m.module)
|
||||
|
||||
@@ -41,7 +41,8 @@ type
|
||||
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
|
||||
ctFloat, ctFloat32, ctFloat64, ctFloat128,
|
||||
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
|
||||
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
|
||||
ctCString
|
||||
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
|
||||
TCProcSection* = enum # the sections a generated C proc consists of
|
||||
cpsLocals, # section of local variables for C proc
|
||||
@@ -57,17 +58,20 @@ type
|
||||
sections*: TCProcSections # the code beloging
|
||||
isLoop*: bool # whether block is a loop
|
||||
nestedTryStmts*: int16 # how many try statements is it nested into
|
||||
nestedExceptStmts*: int16 # how many except statements is it nested into
|
||||
frameLen*: int16
|
||||
|
||||
TCProc{.final.} = object # represents C proc that is currently generated
|
||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
||||
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
||||
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
||||
threadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
inExceptBlock*: int # are we currently inside an except block?
|
||||
# leaving such scopes by raise or by return must
|
||||
# execute any applicable finally blocks
|
||||
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
|
||||
# using return in finally statements
|
||||
labels*: Natural # for generating unique labels in the C proc
|
||||
blocks*: seq[TBlock] # nested blocks
|
||||
breakIdx*: int # the block that will be exited
|
||||
@@ -78,7 +82,7 @@ type
|
||||
maxFrameLen*: int # max length of frame descriptor
|
||||
module*: BModule # used to prevent excessive parameter passing
|
||||
withinLoop*: int # > 0 if we are within a loop
|
||||
gcFrameId*: natural # for the GC stack marking
|
||||
gcFrameId*: Natural # for the GC stack marking
|
||||
gcFrameType*: PRope # the struct {} we put the GC markers into
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
@@ -86,11 +90,12 @@ type
|
||||
module*: PSym
|
||||
filename*: string
|
||||
s*: TCFileSections # sections of the C file
|
||||
PreventStackTrace*: bool # true if stack traces need to be prevented
|
||||
preventStackTrace*: bool # true if stack traces need to be prevented
|
||||
usesThreadVars*: bool # true if the module uses a thread var
|
||||
FrameDeclared*: bool # hack for ROD support so that we don't declare
|
||||
frameDeclared*: bool # hack for ROD support so that we don't declare
|
||||
# a frame var twice in an init proc
|
||||
isHeaderFile*: bool # C source file is the header file
|
||||
includesStringh*: bool # C source file already includes ``<string.h>``
|
||||
cfilename*: string # filename of the module (including path,
|
||||
# without extension)
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
@@ -100,21 +105,21 @@ type
|
||||
headerFiles*: TLinkedList # needed headers to include
|
||||
typeInfoMarker*: TIntSet # needed for generating type information
|
||||
initProc*: BProc # code for init procedure
|
||||
postInitProc*: BProc # code to be executed after the init proc
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
# used for initialization code for
|
||||
# .global. variables
|
||||
# (or instantiated generic variables)
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
forwardedProcs*: TSymSeq # keep forwarded procs here
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
typeNodesName*, nimTypesName*: PRope # used for type info generation
|
||||
labels*: natural # for generating unique module-scope names
|
||||
labels*: Natural # for generating unique module-scope names
|
||||
extensionLoaders*: array['0'..'9', PRope] # special procs for the
|
||||
# OpenGL wrapper
|
||||
injectStmt*: PRope
|
||||
|
||||
var
|
||||
mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module
|
||||
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
|
||||
# varuious parts of the main module
|
||||
gMapping*: PRope # the generated mapping file (if requested)
|
||||
gModules*: seq[BModule] = @[] # list of all compiled modules
|
||||
gForwardedProcsCounter*: int = 0
|
||||
@@ -139,8 +144,9 @@ proc newProc*(prc: PSym, module: BModule): BProc =
|
||||
else: result.options = gOptions
|
||||
newSeq(result.blocks, 1)
|
||||
result.nestedTryStmts = @[]
|
||||
result.finallySafePoints = @[]
|
||||
|
||||
iterator cgenModules*: var BModule =
|
||||
iterator cgenModules*: BModule =
|
||||
for i in 0..high(gModules):
|
||||
# ultimately, we are iterating over the file ids here.
|
||||
# some "files" won't have an associated cgen module (like stdin)
|
||||
|
||||
@@ -18,16 +18,16 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
|
||||
var source = skipTypes(n.typ, abstractPtrs)
|
||||
if (source.kind == tyObject) and (dest.kind == tyObject):
|
||||
var diff = inheritanceDiff(dest, source)
|
||||
if diff == high(int): InternalError(n.info, "cgmeth.genConv")
|
||||
if diff == high(int): internalError(n.info, "cgmeth.genConv")
|
||||
if diff < 0:
|
||||
result = newNodeIT(nkObjUpConv, n.info, d)
|
||||
addSon(result, n)
|
||||
if downCast: InternalError(n.info, "cgmeth.genConv: no upcast allowed")
|
||||
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
|
||||
elif diff > 0:
|
||||
result = newNodeIT(nkObjDownConv, n.info, d)
|
||||
addSon(result, n)
|
||||
if not downCast:
|
||||
InternalError(n.info, "cgmeth.genConv: no downcast allowed")
|
||||
if not downcast:
|
||||
internalError(n.info, "cgmeth.genConv: no downcast allowed")
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
@@ -59,14 +59,14 @@ proc sameMethodBucket(a, b: PSym): bool =
|
||||
aa = skipTypes(aa, {tyGenericInst})
|
||||
bb = skipTypes(bb, {tyGenericInst})
|
||||
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
|
||||
aa = aa.sons[0]
|
||||
bb = bb.sons[0]
|
||||
aa = aa.lastSon
|
||||
bb = bb.lastSon
|
||||
else:
|
||||
break
|
||||
if sameType(aa, bb) or
|
||||
(aa.kind == tyObject) and (bb.kind == tyObject) and
|
||||
(inheritanceDiff(bb, aa) < 0):
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
return
|
||||
result = true
|
||||
@@ -112,12 +112,12 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||
if t.kind == tyObject:
|
||||
for i in countup(1, high(methods)):
|
||||
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
|
||||
if not SameType(t2, t):
|
||||
if not sameType(t2, t):
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
||||
for col in countup(1, sonsLen(a.typ) - 1):
|
||||
if Contains(relevantCols, col):
|
||||
if contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||
var bb = skipTypes(b.typ.sons[col], skipPtrs)
|
||||
var d = inheritanceDiff(aa, bb)
|
||||
@@ -126,14 +126,14 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
||||
|
||||
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
|
||||
# we use shellsort here; fast and simple
|
||||
var N = len(a)
|
||||
var n = len(a)
|
||||
var h = 1
|
||||
while true:
|
||||
h = 3 * h + 1
|
||||
if h > N: break
|
||||
if h > n: break
|
||||
while true:
|
||||
h = h div 3
|
||||
for i in countup(h, N - 1):
|
||||
for i in countup(h, n - 1):
|
||||
var v = a[i]
|
||||
var j = i
|
||||
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
|
||||
@@ -154,7 +154,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
|
||||
var curr = methods[meth] # generate condition:
|
||||
var cond: PNode = nil
|
||||
for col in countup(1, paramLen - 1):
|
||||
if Contains(relevantCols, col):
|
||||
if contains(relevantCols, col):
|
||||
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
addSon(isn, newSymNode(iss))
|
||||
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
|
||||
@@ -195,7 +195,7 @@ proc generateMethodDispatchers*(): PNode =
|
||||
for bucket in countup(0, len(gMethods) - 1):
|
||||
var relevantCols = initIntSet()
|
||||
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1):
|
||||
if relevantCol(gMethods[bucket], col): Incl(relevantCols, col)
|
||||
if relevantCol(gMethods[bucket], col): incl(relevantCols, col)
|
||||
sortBucket(gMethods[bucket], relevantCols)
|
||||
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
const
|
||||
CharSize* = SizeOf(Char)
|
||||
Lrz* = ' '
|
||||
Apo* = '\''
|
||||
Tabulator* = '\x09'
|
||||
ESC* = '\x1B'
|
||||
CR* = '\x0D'
|
||||
FF* = '\x0C'
|
||||
LF* = '\x0A'
|
||||
BEL* = '\x07'
|
||||
BACKSPACE* = '\x08'
|
||||
VT* = '\x0B'
|
||||
|
||||
when defined(macos):
|
||||
DirSep == ':'
|
||||
"\n" == CR & ""
|
||||
FirstNLchar == CR
|
||||
PathSep == ';' # XXX: is this correct?
|
||||
else:
|
||||
when defined(unix):
|
||||
DirSep == '/'
|
||||
"\n" == LF & ""
|
||||
FirstNLchar == LF
|
||||
PathSep == ':'
|
||||
else:
|
||||
# windows, dos
|
||||
DirSep == '\\'
|
||||
"\n" == CR + LF
|
||||
FirstNLchar == CR
|
||||
DriveSeparator == ':'
|
||||
PathSep == ';'
|
||||
UpLetters == {'A'..'Z', '\xC0'..'\xDE'}
|
||||
DownLetters == {'a'..'z', '\xDF'..'\xFF'}
|
||||
Numbers == {'0'..'9'}
|
||||
Letters == UpLetters + DownLetters
|
||||
type
|
||||
TCharSet* = set[Char]
|
||||
PCharSet* = ref TCharSet
|
||||
|
||||
# implementation
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
||||
wordrecg, parseutils, babelcmd
|
||||
wordrecg, parseutils, babelcmd, idents
|
||||
|
||||
proc writeCommandLineUsage*()
|
||||
|
||||
@@ -21,40 +21,40 @@ type
|
||||
passCmd2, # second pass over the command line
|
||||
passPP # preprocessor called ProcessCommand()
|
||||
|
||||
proc ProcessCommand*(switch: string, pass: TCmdLinePass)
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdlinePass, info: TLineInfo)
|
||||
proc processCommand*(switch: string, pass: TCmdLinePass)
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
||||
|
||||
# implementation
|
||||
|
||||
const
|
||||
HelpMessage = "Nimrod Compiler Version $1 (" & compileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2004-2013 by Andreas Rumpf\n"
|
||||
HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
|
||||
|
||||
const
|
||||
Usage = slurp"doc/basicopt.txt".replace("//", "")
|
||||
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
|
||||
|
||||
proc getCommandLineDesc(): string =
|
||||
result = (HelpMessage % [VersionAsString, platform.os[platform.hostOS].name,
|
||||
cpu[platform.hostCPU].name]) & Usage
|
||||
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]) & Usage
|
||||
|
||||
proc HelpOnError(pass: TCmdLinePass) =
|
||||
proc helpOnError(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
MsgWriteln(getCommandLineDesc())
|
||||
msgWriteln(getCommandLineDesc())
|
||||
quit(0)
|
||||
|
||||
proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
MsgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.os[platform.hostOS].name,
|
||||
cpu[platform.hostCPU].name]) & AdvancedUsage)
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]) & AdvancedUsage)
|
||||
quit(0)
|
||||
|
||||
proc writeVersionInfo(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
MsgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.os[platform.hostOS].name,
|
||||
cpu[platform.hostCPU].name]))
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]))
|
||||
quit(0)
|
||||
|
||||
var
|
||||
@@ -62,16 +62,16 @@ var
|
||||
|
||||
proc writeCommandLineUsage() =
|
||||
if not helpWritten:
|
||||
MsgWriteln(getCommandLineDesc())
|
||||
msgWriteln(getCommandLineDesc())
|
||||
helpWritten = true
|
||||
|
||||
proc addPrefix(switch: string): string =
|
||||
if len(switch) == 1: result = "-" & switch
|
||||
else: result = "--" & switch
|
||||
|
||||
proc InvalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
|
||||
if switch == " ": LocalError(info, errInvalidCmdLineOption, "-")
|
||||
else: LocalError(info, errInvalidCmdLineOption, addPrefix(switch))
|
||||
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
|
||||
if switch == " ": localError(info, errInvalidCmdLineOption, "-")
|
||||
else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
|
||||
|
||||
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
@@ -86,29 +86,29 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
|
||||
inc(i)
|
||||
if i >= len(switch): arg = ""
|
||||
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
|
||||
else: InvalidCmdLineOption(pass, switch, info)
|
||||
else: invalidCmdLineOption(pass, switch, info)
|
||||
|
||||
proc ProcessOnOffSwitch(op: TOptions, arg: string, pass: TCmdlinePass,
|
||||
proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
case whichKeyword(arg)
|
||||
of wOn: gOptions = gOptions + op
|
||||
of wOff: gOptions = gOptions - op
|
||||
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc ProcessOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdlinePass,
|
||||
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
case whichKeyword(arg)
|
||||
of wOn: gGlobalOptions = gGlobalOptions + op
|
||||
of wOff: gGlobalOptions = gGlobalOptions - op
|
||||
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc ExpectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg == "": LocalError(info, errCmdLineArgExpected, addPrefix(switch))
|
||||
proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
|
||||
|
||||
proc ExpectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg != "": LocalError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
||||
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
||||
|
||||
proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
|
||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
var id = "" # arg = "X]:on|off"
|
||||
var i = 0
|
||||
@@ -117,21 +117,21 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
|
||||
add(id, arg[i])
|
||||
inc(i)
|
||||
if i < len(arg) and (arg[i] == ']'): inc(i)
|
||||
else: InvalidCmdLineOption(pass, arg, info)
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
||||
else: InvalidCmdLineOption(pass, arg, info)
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
if state == wHint:
|
||||
var x = findStr(msgs.HintsToStr, id)
|
||||
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
||||
else: InvalidCmdLineOption(pass, arg, info)
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
else:
|
||||
var x = findStr(msgs.WarningsToStr, id)
|
||||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
||||
else: InvalidCmdLineOption(pass, arg, info)
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
case whichKeyword(substr(arg, i))
|
||||
of wOn: incl(gNotes, n)
|
||||
of wOff: excl(gNotes, n)
|
||||
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processCompile(filename: string) =
|
||||
var found = findFile(filename)
|
||||
@@ -150,14 +150,14 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
||||
of "markandsweep": result = gSelectedGC == gcMarkAndSweep
|
||||
of "generational": result = gSelectedGC == gcGenerational
|
||||
of "none": result = gSelectedGC == gcNone
|
||||
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
of "opt":
|
||||
case arg.normalize
|
||||
of "speed": result = contains(gOptions, optOptimizeSpeed)
|
||||
of "size": result = contains(gOptions, optOptimizeSize)
|
||||
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
|
||||
else: LocalError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
else: InvalidCmdLineOption(passCmd1, switch, info)
|
||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
case switch.normalize
|
||||
@@ -173,11 +173,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
of "linetrace": result = contains(gOptions, optLineTrace)
|
||||
of "debugger": result = contains(gOptions, optEndb)
|
||||
of "profiler": result = contains(gOptions, optProfiler)
|
||||
of "checks", "x": result = gOptions * checksOptions == checksOptions
|
||||
of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
|
||||
of "floatchecks":
|
||||
result = gOptions * {optNanCheck, optInfCheck} == {optNanCheck, optInfCheck}
|
||||
result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
|
||||
of "infchecks": result = contains(gOptions, optInfCheck)
|
||||
of "nanchecks": result = contains(gOptions, optNanCheck)
|
||||
of "nanchecks": result = contains(gOptions, optNaNCheck)
|
||||
of "objchecks": result = contains(gOptions, optObjCheck)
|
||||
of "fieldchecks": result = contains(gOptions, optFieldCheck)
|
||||
of "rangechecks": result = contains(gOptions, optRangeCheck)
|
||||
@@ -194,7 +194,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
|
||||
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
|
||||
of "patterns": result = contains(gOptions, optPatterns)
|
||||
else: InvalidCmdLineOption(passCmd1, switch, info)
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc processPath(path: string, notRelativeToProj = false): string =
|
||||
let p = if notRelativeToProj or os.isAbsolute(path) or
|
||||
@@ -202,20 +202,20 @@ proc processPath(path: string, notRelativeToProj = false): string =
|
||||
path
|
||||
else:
|
||||
options.gProjectPath / path
|
||||
result = UnixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
|
||||
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
|
||||
"home", removeTrailingDirSep(os.getHomeDir()),
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath])
|
||||
|
||||
proc trackDirty(arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 4: LocalError(info, errTokenExpected,
|
||||
if a.len != 4: localError(info, errTokenExpected,
|
||||
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
|
||||
var line, column: int
|
||||
if parseUtils.parseInt(a[2], line) <= 0:
|
||||
LocalError(info, errInvalidNumber, a[1])
|
||||
localError(info, errInvalidNumber, a[1])
|
||||
if parseUtils.parseInt(a[3], column) <= 0:
|
||||
LocalError(info, errInvalidNumber, a[2])
|
||||
localError(info, errInvalidNumber, a[2])
|
||||
|
||||
gDirtyBufferIdx = a[0].fileInfoIdx
|
||||
gDirtyOriginalIdx = a[1].fileInfoIdx
|
||||
@@ -225,21 +225,21 @@ proc trackDirty(arg: string, info: TLineInfo) =
|
||||
|
||||
proc track(arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLUMN")
|
||||
if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
|
||||
var line, column: int
|
||||
if parseUtils.parseInt(a[1], line) <= 0:
|
||||
LocalError(info, errInvalidNumber, a[1])
|
||||
localError(info, errInvalidNumber, a[1])
|
||||
if parseUtils.parseInt(a[2], column) <= 0:
|
||||
LocalError(info, errInvalidNumber, a[2])
|
||||
localError(info, errInvalidNumber, a[2])
|
||||
optTrackPos = newLineInfo(a[0], line, column)
|
||||
msgs.addCheckpoint(optTrackPos)
|
||||
|
||||
proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if pass in {passCmd2, passPP}:
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.inclDynlibOverride(arg)
|
||||
|
||||
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
var
|
||||
theOS: TSystemOS
|
||||
cpu: TSystemCPU
|
||||
@@ -249,30 +249,36 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
expectArg(switch, arg, pass, info)
|
||||
addPath(processPath(arg), info)
|
||||
of "babelpath":
|
||||
if pass in {passCmd2, passPP}:
|
||||
if pass in {passCmd2, passPP} and not options.gNoBabelPath:
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg, notRelativeToProj=true)
|
||||
babelpath(path, info)
|
||||
of "nobabelpath":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
options.gNoBabelPath = true
|
||||
of "excludepath":
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg)
|
||||
lists.ExcludeStr(options.searchPaths, path)
|
||||
lists.ExcludeStr(options.lazyPaths, path)
|
||||
lists.excludeStr(options.searchPaths, path)
|
||||
lists.excludeStr(options.lazyPaths, path)
|
||||
of "nimcache":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.nimcacheDir = processPath(arg)
|
||||
of "out", "o":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.outFile = arg
|
||||
of "docseesrcurl":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.docSeeSrcUrl = arg
|
||||
of "mainmodule", "m":
|
||||
expectArg(switch, arg, pass, info)
|
||||
optMainModule = arg
|
||||
of "define", "d":
|
||||
expectArg(switch, arg, pass, info)
|
||||
DefineSymbol(arg)
|
||||
defineSymbol(arg)
|
||||
of "undef", "u":
|
||||
expectArg(switch, arg, pass, info)
|
||||
UndefSymbol(arg)
|
||||
undefSymbol(arg)
|
||||
of "compile":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: processCompile(arg)
|
||||
@@ -305,7 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
case arg.normalize
|
||||
of "boehm":
|
||||
gSelectedGC = gcBoehm
|
||||
DefineSymbol("boehmgc")
|
||||
defineSymbol("boehmgc")
|
||||
of "refc":
|
||||
gSelectedGC = gcRefc
|
||||
of "v2":
|
||||
@@ -319,42 +325,42 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
of "none":
|
||||
gSelectedGC = gcNone
|
||||
defineSymbol("nogc")
|
||||
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
of "warnings", "w": ProcessOnOffSwitch({optWarns}, arg, pass, info)
|
||||
of "warning": ProcessSpecificNote(arg, wWarning, pass, info)
|
||||
of "hint": ProcessSpecificNote(arg, wHint, pass, info)
|
||||
of "hints": ProcessOnOffSwitch({optHints}, arg, pass, info)
|
||||
of "threadanalysis": ProcessOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
||||
of "stacktrace": ProcessOnOffSwitch({optStackTrace}, arg, pass, info)
|
||||
of "linetrace": ProcessOnOffSwitch({optLineTrace}, arg, pass, info)
|
||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
|
||||
of "warning": processSpecificNote(arg, wWarning, pass, info)
|
||||
of "hint": processSpecificNote(arg, wHint, pass, info)
|
||||
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
|
||||
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
||||
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
||||
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
|
||||
of "debugger":
|
||||
ProcessOnOffSwitch({optEndb}, arg, pass, info)
|
||||
if optEndb in gOptions: DefineSymbol("endb")
|
||||
else: UndefSymbol("endb")
|
||||
processOnOffSwitch({optEndb}, arg, pass, info)
|
||||
if optEndb in gOptions: defineSymbol("endb")
|
||||
else: undefSymbol("endb")
|
||||
of "profiler":
|
||||
ProcessOnOffSwitch({optProfiler}, arg, pass, info)
|
||||
if optProfiler in gOptions: DefineSymbol("profiler")
|
||||
else: UndefSymbol("profiler")
|
||||
of "checks", "x": ProcessOnOffSwitch(checksOptions, arg, pass, info)
|
||||
processOnOffSwitch({optProfiler}, arg, pass, info)
|
||||
if optProfiler in gOptions: defineSymbol("profiler")
|
||||
else: undefSymbol("profiler")
|
||||
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
|
||||
of "floatchecks":
|
||||
ProcessOnOffSwitch({optNanCheck, optInfCheck}, arg, pass, info)
|
||||
of "infchecks": ProcessOnOffSwitch({optInfCheck}, arg, pass, info)
|
||||
of "nanchecks": ProcessOnOffSwitch({optNanCheck}, arg, pass, info)
|
||||
of "objchecks": ProcessOnOffSwitch({optObjCheck}, arg, pass, info)
|
||||
of "fieldchecks": ProcessOnOffSwitch({optFieldCheck}, arg, pass, info)
|
||||
of "rangechecks": ProcessOnOffSwitch({optRangeCheck}, arg, pass, info)
|
||||
of "boundchecks": ProcessOnOffSwitch({optBoundsCheck}, arg, pass, info)
|
||||
of "overflowchecks": ProcessOnOffSwitch({optOverflowCheck}, arg, pass, info)
|
||||
of "linedir": ProcessOnOffSwitch({optLineDir}, arg, pass, info)
|
||||
of "assertions", "a": ProcessOnOffSwitch({optAssert}, arg, pass, info)
|
||||
of "deadcodeelim": ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||
of "threads": ProcessOnOffSwitchG({optThreads}, arg, pass, info)
|
||||
of "tlsemulation": ProcessOnOffSwitchG({optTlsEmulation}, arg, pass, info)
|
||||
of "taintmode": ProcessOnOffSwitchG({optTaintMode}, arg, pass, info)
|
||||
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
|
||||
of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
|
||||
of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
|
||||
of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
|
||||
of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
|
||||
of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
|
||||
of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
|
||||
of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
|
||||
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
|
||||
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
|
||||
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||
of "threads": processOnOffSwitchG({optThreads}, arg, pass, info)
|
||||
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
|
||||
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
|
||||
of "implicitstatic":
|
||||
ProcessOnOffSwitch({optImplicitStatic}, arg, pass, info)
|
||||
processOnOffSwitch({optImplicitStatic}, arg, pass, info)
|
||||
of "patterns":
|
||||
ProcessOnOffSwitch({optPatterns}, arg, pass, info)
|
||||
processOnOffSwitch({optPatterns}, arg, pass, info)
|
||||
of "opt":
|
||||
expectArg(switch, arg, pass, info)
|
||||
case arg.normalize
|
||||
@@ -367,7 +373,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
of "none":
|
||||
excl(gOptions, optOptimizeSpeed)
|
||||
excl(gOptions, optOptimizeSize)
|
||||
else: LocalError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
of "app":
|
||||
expectArg(switch, arg, pass, info)
|
||||
case arg.normalize
|
||||
@@ -389,7 +395,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
excl(gGlobalOptions, optGenGuiApp)
|
||||
defineSymbol("library")
|
||||
defineSymbol("staticlib")
|
||||
else: LocalError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
||||
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
||||
of "passc", "t":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
|
||||
@@ -398,18 +404,18 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
|
||||
of "cincludes":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cIncludes.add arg
|
||||
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath
|
||||
of "clibdir":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cLibs.add arg
|
||||
if pass in {passCmd2, passPP}: cLibs.add arg.processPath
|
||||
of "clib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg
|
||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath
|
||||
of "header":
|
||||
headerFile = arg
|
||||
incl(gGlobalOptions, optGenIndex)
|
||||
of "index":
|
||||
ProcessOnOffSwitchG({optGenIndex}, arg, pass, info)
|
||||
processOnOffSwitchG({optGenIndex}, arg, pass, info)
|
||||
of "import":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: implicitImports.add arg
|
||||
@@ -425,19 +431,19 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
of "os":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd1, passPP}:
|
||||
theOS = platform.NameToOS(arg)
|
||||
if theOS == osNone: LocalError(info, errUnknownOS, arg)
|
||||
theOS = platform.nameToOS(arg)
|
||||
if theOS == osNone: localError(info, errUnknownOS, arg)
|
||||
elif theOS != platform.hostOS:
|
||||
setTarget(theOS, targetCPU)
|
||||
condsyms.InitDefines()
|
||||
condsyms.initDefines()
|
||||
of "cpu":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd1, passPP}:
|
||||
cpu = platform.NameToCPU(arg)
|
||||
if cpu == cpuNone: LocalError(info, errUnknownCPU, arg)
|
||||
cpu = platform.nameToCPU(arg)
|
||||
if cpu == cpuNone: localError(info, errUnknownCPU, arg)
|
||||
elif cpu != platform.hostCPU:
|
||||
setTarget(targetOS, cpu)
|
||||
condsyms.InitDefines()
|
||||
condsyms.initDefines()
|
||||
of "run", "r":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optRun)
|
||||
@@ -457,7 +463,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
helpOnError(pass)
|
||||
of "symbolfiles":
|
||||
ProcessOnOffSwitchG({optSymbolFiles}, arg, pass, info)
|
||||
processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
|
||||
of "skipcfg":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optSkipConfigFile)
|
||||
@@ -512,11 +518,18 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
gListFullPaths = true
|
||||
of "dynliboverride":
|
||||
dynlibOverride(switch, arg, pass, info)
|
||||
of "cs":
|
||||
expectArg(switch, arg, pass, info)
|
||||
case arg
|
||||
of "partial": idents.firstCharIsCS = true
|
||||
of "none": idents.firstCharIsCS = false
|
||||
else: localError(info, errGenerated,
|
||||
"'partial' or 'none' expected, but found " & arg)
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||
else: InvalidCmdLineOption(pass, switch, info)
|
||||
else: invalidCmdLineOption(pass, switch, info)
|
||||
|
||||
proc ProcessCommand(switch: string, pass: TCmdLinePass) =
|
||||
proc processCommand(switch: string, pass: TCmdLinePass) =
|
||||
var cmd, arg: string
|
||||
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
||||
processSwitch(cmd, arg, pass, gCmdLineInfo)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -10,93 +10,82 @@
|
||||
# This module handles the conditional symbols.
|
||||
|
||||
import
|
||||
ast, astalgo, hashes, platform, strutils, idents
|
||||
strtabs, platform, strutils, idents
|
||||
|
||||
var gSymbols*: TStrTable
|
||||
# We need to use a PStringTable here as defined symbols are always guaranteed
|
||||
# to be style insensitive. Otherwise hell would break lose.
|
||||
var gSymbols: PStringTable
|
||||
|
||||
proc DefineSymbol*(symbol: string) =
|
||||
var i = getIdent(symbol)
|
||||
var sym = StrTableGet(gSymbols, i)
|
||||
if sym == nil:
|
||||
new(sym) # circumvent the ID mechanism
|
||||
sym.kind = skConditional
|
||||
sym.name = i
|
||||
StrTableAdd(gSymbols, sym)
|
||||
sym.position = 1
|
||||
proc defineSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "true"
|
||||
|
||||
proc UndefSymbol*(symbol: string) =
|
||||
var sym = StrTableGet(gSymbols, getIdent(symbol))
|
||||
if sym != nil: sym.position = 0
|
||||
|
||||
proc isDefined*(symbol: PIdent): bool =
|
||||
var sym = StrTableGet(gSymbols, symbol)
|
||||
result = sym != nil and sym.position == 1
|
||||
proc undefSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "false"
|
||||
|
||||
proc isDefined*(symbol: string): bool =
|
||||
result = isDefined(getIdent(symbol))
|
||||
if gSymbols.hasKey(symbol):
|
||||
result = gSymbols[symbol] == "true"
|
||||
|
||||
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
||||
|
||||
iterator definedSymbolNames*: string =
|
||||
var it: TTabIter
|
||||
var s = InitTabIter(it, gSymbols)
|
||||
while s != nil:
|
||||
if s.position == 1: yield s.name.s
|
||||
s = nextIter(it, gSymbols)
|
||||
for key, val in pairs(gSymbols):
|
||||
if val == "true": yield key
|
||||
|
||||
proc countDefinedSymbols*(): int =
|
||||
var it: TTabIter
|
||||
var s = InitTabIter(it, gSymbols)
|
||||
result = 0
|
||||
while s != nil:
|
||||
if s.position == 1: inc(result)
|
||||
s = nextIter(it, gSymbols)
|
||||
for key, val in pairs(gSymbols):
|
||||
if val == "true": inc(result)
|
||||
|
||||
proc InitDefines*() =
|
||||
initStrTable(gSymbols)
|
||||
DefineSymbol("nimrod") # 'nimrod' is always defined
|
||||
proc initDefines*() =
|
||||
gSymbols = newStringTable(modeStyleInsensitive)
|
||||
defineSymbol("nimrod") # 'nimrod' is always defined
|
||||
# for bootstrapping purposes and old code:
|
||||
DefineSymbol("nimhygiene")
|
||||
DefineSymbol("niminheritable")
|
||||
DefineSymbol("nimmixin")
|
||||
DefineSymbol("nimeffects")
|
||||
DefineSymbol("nimbabel")
|
||||
defineSymbol("nimhygiene")
|
||||
defineSymbol("niminheritable")
|
||||
defineSymbol("nimmixin")
|
||||
defineSymbol("nimeffects")
|
||||
defineSymbol("nimbabel")
|
||||
defineSymbol("nimcomputedgoto")
|
||||
defineSymbol("nimunion")
|
||||
defineSymbol("nimnewshared")
|
||||
defineSymbol("nimrequiresnimframe")
|
||||
|
||||
# add platform specific symbols:
|
||||
case targetCPU
|
||||
of cpuI386: DefineSymbol("x86")
|
||||
of cpuIa64: DefineSymbol("itanium")
|
||||
of cpuAmd64: DefineSymbol("x8664")
|
||||
else: nil
|
||||
of cpuI386: defineSymbol("x86")
|
||||
of cpuIa64: defineSymbol("itanium")
|
||||
of cpuAmd64: defineSymbol("x8664")
|
||||
else: discard
|
||||
case targetOS
|
||||
of osDOS:
|
||||
DefineSymbol("msdos")
|
||||
of osDos:
|
||||
defineSymbol("msdos")
|
||||
of osWindows:
|
||||
DefineSymbol("mswindows")
|
||||
DefineSymbol("win32")
|
||||
of osLinux, osMorphOS, osSkyOS, osIrix, osPalmOS, osQNX, osAtari, osAix,
|
||||
defineSymbol("mswindows")
|
||||
defineSymbol("win32")
|
||||
of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix,
|
||||
osHaiku:
|
||||
# these are all 'unix-like'
|
||||
DefineSymbol("unix")
|
||||
DefineSymbol("posix")
|
||||
defineSymbol("unix")
|
||||
defineSymbol("posix")
|
||||
of osSolaris:
|
||||
DefineSymbol("sunos")
|
||||
DefineSymbol("unix")
|
||||
DefineSymbol("posix")
|
||||
of osNetBSD, osFreeBSD, osOpenBSD:
|
||||
DefineSymbol("unix")
|
||||
DefineSymbol("bsd")
|
||||
DefineSymbol("posix")
|
||||
of osMacOS:
|
||||
DefineSymbol("macintosh")
|
||||
of osMacOSX:
|
||||
DefineSymbol("macintosh")
|
||||
DefineSymbol("unix")
|
||||
DefineSymbol("posix")
|
||||
else: nil
|
||||
DefineSymbol("cpu" & $cpu[targetCPU].bit)
|
||||
DefineSymbol(normalize(endianToStr[cpu[targetCPU].endian]))
|
||||
DefineSymbol(cpu[targetCPU].name)
|
||||
DefineSymbol(platform.os[targetOS].name)
|
||||
defineSymbol("sunos")
|
||||
defineSymbol("unix")
|
||||
defineSymbol("posix")
|
||||
of osNetbsd, osFreebsd, osOpenbsd:
|
||||
defineSymbol("unix")
|
||||
defineSymbol("bsd")
|
||||
defineSymbol("posix")
|
||||
of osMacos:
|
||||
defineSymbol("macintosh")
|
||||
of osMacosx:
|
||||
defineSymbol("macintosh")
|
||||
defineSymbol("unix")
|
||||
defineSymbol("posix")
|
||||
else: discard
|
||||
defineSymbol("cpu" & $CPU[targetCPU].bit)
|
||||
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
|
||||
defineSymbol(CPU[targetCPU].name)
|
||||
defineSymbol(platform.OS[targetOS].name)
|
||||
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
|
||||
DefineSymbol("emulatedthreadvars")
|
||||
|
||||
|
||||
defineSymbol("emulatedthreadvars")
|
||||
|
||||
@@ -18,8 +18,8 @@ const
|
||||
InitAdler32* = int32(1)
|
||||
|
||||
proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
|
||||
proc updateCrc32*(val: Char, crc: TCrc32): TCrc32 {.inline.}
|
||||
proc crcFromBuf*(buf: Pointer, length: int): TCrc32
|
||||
proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
|
||||
proc crcFromBuf*(buf: pointer, length: int): TCrc32
|
||||
proc strCrc32*(s: string): TCrc32
|
||||
proc crcFromFile*(filename: string): TCrc32
|
||||
proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
|
||||
@@ -75,10 +75,10 @@ const
|
||||
755167117]
|
||||
|
||||
proc updateCrc32(val: int8, crc: TCrc32): TCrc32 =
|
||||
result = TCrc32(crc32Table[(int(crc) xor (int(val) and 0x000000FF)) and
|
||||
result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
|
||||
0x000000FF]) xor (crc shr TCrc32(8))
|
||||
|
||||
proc updateCrc32(val: Char, crc: TCrc32): TCrc32 =
|
||||
proc updateCrc32(val: char, crc: TCrc32): TCrc32 =
|
||||
result = updateCrc32(toU8(ord(val)), crc)
|
||||
|
||||
proc strCrc32(s: string): TCrc32 =
|
||||
@@ -93,7 +93,7 @@ type
|
||||
TByteArray = array[0..10000000, int8]
|
||||
PByteArray = ref TByteArray
|
||||
|
||||
proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
|
||||
proc crcFromBuf(buf: pointer, length: int): TCrc32 =
|
||||
var p = cast[PByteArray](buf)
|
||||
result = InitCrc32
|
||||
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
|
||||
@@ -102,11 +102,11 @@ proc crcFromFile(filename: string): TCrc32 =
|
||||
const
|
||||
bufSize = 8000 # don't use 8K for the memory allocator!
|
||||
var
|
||||
bin: tfile
|
||||
bin: TFile
|
||||
result = InitCrc32
|
||||
if not open(bin, filename):
|
||||
return # not equal if file does not exist
|
||||
var buf = alloc(BufSize)
|
||||
var buf = alloc(bufSize)
|
||||
var p = cast[PByteArray](buf)
|
||||
while true:
|
||||
var readBytes = readBuffer(bin, buf, bufSize)
|
||||
|
||||
@@ -39,11 +39,11 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
|
||||
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
proc generateDot(project: string) =
|
||||
writeRope(ropef("digraph $1 {$n$2}$n", [
|
||||
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]),
|
||||
toRope(changeFileExt(extractFilename(project), "")), gDotGraph]),
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
# semantic checking is done for the code. Cross-references are generated
|
||||
# by knowing how the anchors are going to be named.
|
||||
|
||||
import
|
||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
||||
importer, sempass2
|
||||
import
|
||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
||||
importer, sempass2, json, xmltree, cgi, typesrenderer
|
||||
|
||||
type
|
||||
TSections = array[TSymKind, PRope]
|
||||
@@ -23,9 +23,10 @@ type
|
||||
id: int # for generating IDs
|
||||
toc, section: TSections
|
||||
indexValFilename: string
|
||||
seenSymbols: PStringTable # avoids duplicate symbol generation for HTML.
|
||||
|
||||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
||||
PDoc* = ref TDocumentor
|
||||
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
|
||||
# translate msg kind:
|
||||
@@ -40,70 +41,77 @@ proc compilerMsgHandler(filename: string, line, col: int,
|
||||
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
|
||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||
GlobalError(newLineInfo(filename, line, col), k, arg)
|
||||
|
||||
globalError(newLineInfo(filename, line, col), k, arg)
|
||||
|
||||
proc docgenFindFile(s: string): string {.procvar.} =
|
||||
result = options.findFile(s)
|
||||
if result.len == 0:
|
||||
result = getCurrentDir() / s
|
||||
if not existsFile(result): result = ""
|
||||
|
||||
proc parseRst(text, filename: string,
|
||||
line, column: int, hasToc: var bool,
|
||||
rstOptions: TRstParseOptions): PRstNode =
|
||||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||
options.FindFile, compilerMsgHandler)
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
|
||||
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
|
||||
new(result)
|
||||
initRstGenerator(result[], (if gCmd != cmdRst2Tex: outHtml else: outLatex),
|
||||
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
|
||||
options.gConfigVars, filename, {roSupportRawDirective},
|
||||
options.FindFile, compilerMsgHandler)
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
result.seenSymbols = newStringTable(modeCaseInsensitive)
|
||||
result.id = 100
|
||||
|
||||
proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) =
|
||||
if gCmd != cmdRst2Tex: appf(dest, xml, args)
|
||||
proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) =
|
||||
if gCmd != cmdRst2tex: appf(dest, xml, args)
|
||||
else: appf(dest, tex, args)
|
||||
|
||||
proc getVarIdx(varnames: openarray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
|
||||
proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
return i
|
||||
result = -1
|
||||
|
||||
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
|
||||
varvalues: openarray[PRope]): PRope =
|
||||
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
varvalues: openArray[PRope]): PRope =
|
||||
var i = 0
|
||||
var L = len(frmt)
|
||||
result = nil
|
||||
var num = 0
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '#':
|
||||
of '#':
|
||||
app(result, varvalues[num])
|
||||
inc(num)
|
||||
inc(i)
|
||||
of '$':
|
||||
of '$':
|
||||
app(result, "$")
|
||||
inc(i)
|
||||
of '0'..'9':
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||
while true:
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
|
||||
num = j
|
||||
app(result, varvalues[j - 1])
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
var id = ""
|
||||
while true:
|
||||
while true:
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
else: rawMessage(errUnkownSubstitionVar, id)
|
||||
of '{':
|
||||
of '{':
|
||||
var id = ""
|
||||
inc(i)
|
||||
while frmt[i] != '}':
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
@@ -112,7 +120,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
else: rawMessage(errUnkownSubstitionVar, id)
|
||||
else: InternalError("ropeFormatNamedVars")
|
||||
else: internalError("ropeFormatNamedVars")
|
||||
var start = i
|
||||
while i < L:
|
||||
if frmt[i] != '$': inc(i)
|
||||
@@ -124,20 +132,37 @@ proc genComment(d: PDoc, n: PNode): string =
|
||||
var dummyHasToc: bool
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
||||
toLineNumber(n.info), toColumn(n.info),
|
||||
toLinenumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options + {roSkipPounds}), result)
|
||||
|
||||
proc genRecComment(d: PDoc, n: PNode): PRope =
|
||||
proc genRecComment(d: PDoc, n: PNode): PRope =
|
||||
if n == nil: return nil
|
||||
result = genComment(d, n).toRope
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
if n.kind notin {nkEmpty..nkNilLit}:
|
||||
for i in countup(0, len(n)-1):
|
||||
result = genRecComment(d, n.sons[i])
|
||||
if result != nil: return
|
||||
if result != nil: return
|
||||
else:
|
||||
n.comment = nil
|
||||
|
||||
proc getPlainDocstring(n: PNode): string =
|
||||
## Gets the plain text docstring of a node non destructively.
|
||||
##
|
||||
## You need to call this before genRecComment, whose side effects are removal
|
||||
## of comments from the tree. The proc will recursively scan and return all
|
||||
## the concatenated ``##`` comments of the node.
|
||||
result = ""
|
||||
if n == nil: return
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
result = n.comment
|
||||
if result.len < 1:
|
||||
if n.kind notin {nkEmpty..nkNilLit}:
|
||||
for i in countup(0, len(n)-1):
|
||||
result = getPlainDocstring(n.sons[i])
|
||||
if result.len > 0: return
|
||||
|
||||
|
||||
proc findDocComment(n: PNode): PNode =
|
||||
if n == nil: return nil
|
||||
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
|
||||
@@ -152,16 +177,16 @@ proc extractDocComment*(s: PSym, d: PDoc = nil): string =
|
||||
if not d.isNil:
|
||||
var dummyHasToc: bool
|
||||
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
||||
toLineNumber(n.info), toColumn(n.info),
|
||||
toLinenumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options + {roSkipPounds}),
|
||||
result)
|
||||
else:
|
||||
result = n.comment.substr(2).replace("\n##", "\n").strip
|
||||
|
||||
proc isVisible(n: PNode): bool =
|
||||
proc isVisible(n: PNode): bool =
|
||||
result = false
|
||||
if n.kind == nkPostfix:
|
||||
if n.len == 2 and n.sons[0].kind == nkIdent:
|
||||
if n.kind == nkPostfix:
|
||||
if n.len == 2 and n.sons[0].kind == nkIdent:
|
||||
var v = n.sons[0].ident
|
||||
result = v.id == ord(wStar) or v.id == ord(wMinus)
|
||||
elif n.kind == nkSym:
|
||||
@@ -171,110 +196,257 @@ proc isVisible(n: PNode): bool =
|
||||
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
||||
elif n.kind == nkPragmaExpr:
|
||||
result = isVisible(n.sons[0])
|
||||
|
||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
|
||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
case n.kind
|
||||
of nkPostfix: result = getName(d, n.sons[1], splitAfter)
|
||||
of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
|
||||
of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
|
||||
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
|
||||
of nkAccQuoted:
|
||||
result = esc(d.target, "`")
|
||||
of nkAccQuoted:
|
||||
result = esc(d.target, "`")
|
||||
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
|
||||
result.add esc(d.target, "`")
|
||||
else:
|
||||
internalError(n.info, "getName()")
|
||||
result = ""
|
||||
|
||||
proc getRstName(n: PNode): PRstNode =
|
||||
proc getRstName(n: PNode): PRstNode =
|
||||
case n.kind
|
||||
of nkPostfix: result = getRstName(n.sons[1])
|
||||
of nkPragmaExpr: result = getRstName(n.sons[0])
|
||||
of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName)
|
||||
of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
|
||||
of nkAccQuoted:
|
||||
of nkAccQuoted:
|
||||
result = getRstName(n.sons[0])
|
||||
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
|
||||
else:
|
||||
internalError(n.info, "getRstName()")
|
||||
result = nil
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(nameNode): return
|
||||
var name = toRope(getName(d, nameNode))
|
||||
proc newUniquePlainSymbol(d: PDoc, original: string): string =
|
||||
## Returns a new unique plain symbol made up from the original.
|
||||
##
|
||||
## When a collision is found in the seenSymbols table, new numerical variants
|
||||
## with underscore + number will be generated.
|
||||
if not d.seenSymbols.hasKey(original):
|
||||
result = original
|
||||
d.seenSymbols[original] = ""
|
||||
return
|
||||
|
||||
# Iterate over possible numeric variants of the original name.
|
||||
var count = 2
|
||||
|
||||
while true:
|
||||
result = original & "_" & $count
|
||||
if not d.seenSymbols.hasKey(result):
|
||||
d.seenSymbols[result] = ""
|
||||
break
|
||||
count += 1
|
||||
|
||||
|
||||
proc complexName(k: TSymKind, n: PNode, baseName: string): string =
|
||||
## Builds a complex unique href name for the node.
|
||||
##
|
||||
## Pass as ``baseName`` the plain symbol obtained from the nodeName. The
|
||||
## format of the returned symbol will be ``baseName(.callable type)?,(param
|
||||
## type)?(,param type)*``. The callable type part will be added only if the
|
||||
## node is not a proc, as those are the common ones. The suffix will be a dot
|
||||
## and a single letter representing the type of the callable. The parameter
|
||||
## types will be added with a preceeding dash. Return types won't be added.
|
||||
##
|
||||
## If you modify the output of this proc, please update the anchor generation
|
||||
## section of ``doc/docgen.txt``.
|
||||
result = baseName
|
||||
case k:
|
||||
of skProc: result.add(defaultParamSeparator)
|
||||
of skMacro: result.add(".m" & defaultParamSeparator)
|
||||
of skMethod: result.add(".e" & defaultParamSeparator)
|
||||
of skIterator: result.add(".i" & defaultParamSeparator)
|
||||
of skTemplate: result.add(".t" & defaultParamSeparator)
|
||||
of skConverter: result.add(".c" & defaultParamSeparator)
|
||||
else: discard
|
||||
|
||||
if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams:
|
||||
result.add(renderParamTypes(n[paramsPos]))
|
||||
|
||||
|
||||
proc isCallable(n: PNode): bool =
|
||||
## Returns true if `n` contains a callable node.
|
||||
case n.kind
|
||||
of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef,
|
||||
nkConverterDef: result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
|
||||
proc docstringSummary(rstText: string): string =
|
||||
## Returns just the first line or a brief chunk of text from a rst string.
|
||||
##
|
||||
## Most docstrings will contain a one liner summary, so stripping at the
|
||||
## first newline is usually fine. If after that the content is still too big,
|
||||
## it is stripped at the first comma, colon or dot, usual english sentence
|
||||
## separators.
|
||||
##
|
||||
## No guarantees are made on the size of the output, but it should be small.
|
||||
## Also, we hope to not break the rst, but maybe we do. If there is any
|
||||
## trimming done, an ellipsis unicode char is added.
|
||||
const maxDocstringChars = 100
|
||||
assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
|
||||
result = rstText.substr(2).strip
|
||||
var pos = result.find('\L')
|
||||
if pos > 0:
|
||||
result.delete(pos, result.len - 1)
|
||||
result.add("…")
|
||||
if pos < maxDocstringChars:
|
||||
return
|
||||
# Try to keep trimming at other natural boundaries.
|
||||
pos = result.find({'.', ',', ':'})
|
||||
let last = result.len - 1
|
||||
if pos > 0 and pos < last:
|
||||
result.delete(pos, last)
|
||||
result.add("…")
|
||||
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(nameNode): return
|
||||
let
|
||||
name = getName(d, nameNode)
|
||||
nameRope = name.toRope
|
||||
plainDocstring = getPlainDocstring(n) # call here before genRecComment!
|
||||
var result: PRope = nil
|
||||
var literal = ""
|
||||
var literal, plainName = ""
|
||||
var kind = tkEof
|
||||
var comm = genRecComment(d, n) # call this here for the side-effect!
|
||||
var r: TSrcGen
|
||||
# Obtain the plain rendered string for hyperlink titles.
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderNoProcDefs})
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
if kind == tkEof:
|
||||
break
|
||||
plainName.add(literal)
|
||||
|
||||
# Render the HTML hyperlink.
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
while true:
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
case kind
|
||||
of tkEof:
|
||||
break
|
||||
of tkComment:
|
||||
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
of tkEof:
|
||||
break
|
||||
of tkComment:
|
||||
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
of tokKeywordLow..tokKeywordHigh:
|
||||
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
of tokKeywordLow..tokKeywordHigh:
|
||||
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
[toRope(literal)])
|
||||
of tkOpr:
|
||||
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
of tkOpr:
|
||||
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
of tkStrLit..tkTripleStrLit:
|
||||
dispA(result, "<span class=\"StringLit\">$1</span>",
|
||||
of tkStrLit..tkTripleStrLit:
|
||||
dispA(result, "<span class=\"StringLit\">$1</span>",
|
||||
"\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkCharLit:
|
||||
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
of tkCharLit:
|
||||
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
of tkIntLit..tkUInt64Lit:
|
||||
dispA(result, "<span class=\"DecNumber\">$1</span>",
|
||||
of tkIntLit..tkUInt64Lit:
|
||||
dispA(result, "<span class=\"DecNumber\">$1</span>",
|
||||
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkFloatLit..tkFloat128Lit:
|
||||
dispA(result, "<span class=\"FloatNumber\">$1</span>",
|
||||
of tkFloatLit..tkFloat128Lit:
|
||||
dispA(result, "<span class=\"FloatNumber\">$1</span>",
|
||||
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
|
||||
of tkSpaces, tkInvalid:
|
||||
of tkSpaces, tkInvalid:
|
||||
app(result, literal)
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
inc(d.id)
|
||||
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
["name", "header", "desc", "itemID"],
|
||||
[name, result, comm, toRope(d.id)]))
|
||||
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
["name", "header", "desc", "itemID"], [
|
||||
toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)]))
|
||||
setIndexTerm(d[], $d.id, getName(d, nameNode))
|
||||
let
|
||||
plainNameRope = toRope(xmltree.escape(plainName.strip))
|
||||
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
||||
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
||||
plainSymbolRope = toRope(cleanPlainSymbol)
|
||||
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol))
|
||||
itemIDRope = toRope(d.id)
|
||||
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
|
||||
symbolOrIdRope = symbolOrId.toRope
|
||||
symbolOrIdEncRope = URLEncode(symbolOrId).toRope
|
||||
|
||||
proc checkForFalse(n: PNode): bool =
|
||||
result = n.kind == nkIdent and IdentEq(n.ident, "false")
|
||||
|
||||
proc traceDeps(d: PDoc, n: PNode) =
|
||||
var seeSrcRope: PRope = nil
|
||||
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
|
||||
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
|
||||
["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)])
|
||||
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
|
||||
["path", "line", "url"], [n.info.toFilename.toRope,
|
||||
toRope($n.info.line), urlRope])])
|
||||
|
||||
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
|
||||
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
|
||||
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
|
||||
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
|
||||
[toRope(getName(d, nameNode, d.splitAfter)), result, comm,
|
||||
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
|
||||
plainSymbolEncRope, symbolOrIdEncRope]))
|
||||
|
||||
# Ironically for types the complexSymbol is *cleaner* than the plainName
|
||||
# because it doesn't include object fields or documentation comments. So we
|
||||
# use the plain one for callable elements, and the complex for the rest.
|
||||
var linkTitle = changeFileExt(extractFilename(d.filename), "") & " : "
|
||||
if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip))
|
||||
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
|
||||
|
||||
setIndexTerm(d[], symbolOrId, name, linkTitle,
|
||||
xmltree.escape(plainDocstring.docstringSummary))
|
||||
|
||||
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
|
||||
if not isVisible(nameNode): return
|
||||
var
|
||||
name = getName(d, nameNode)
|
||||
comm = genRecComment(d, n).ropeToStr()
|
||||
r: TSrcGen
|
||||
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
|
||||
result = %{ "name": %name, "type": %($k) }
|
||||
|
||||
if comm != nil and comm != "":
|
||||
result["description"] = %comm
|
||||
if r.buf != nil:
|
||||
result["code"] = %r.buf
|
||||
|
||||
proc checkForFalse(n: PNode): bool =
|
||||
result = n.kind == nkIdent and identEq(n.ident, "false")
|
||||
|
||||
proc traceDeps(d: PDoc, n: PNode) =
|
||||
const k = skModule
|
||||
if d.section[k] != nil: app(d.section[k], ", ")
|
||||
dispA(d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
dispA(d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
"$1", [toRope(getModuleName(n))])
|
||||
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
of nkCommentStmt: app(d.modDesc, genComment(d, n))
|
||||
of nkProcDef:
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skProc)
|
||||
of nkMethodDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skMethod)
|
||||
of nkIteratorDef:
|
||||
of nkIteratorDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skIterator)
|
||||
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
|
||||
@@ -284,27 +456,69 @@ proc generateDoc*(d: PDoc, n: PNode) =
|
||||
genItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
|
||||
of nkWhenStmt:
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n.sons[0].sons[0]):
|
||||
generateDoc(d, lastSon(n.sons[0]))
|
||||
of nkImportStmt:
|
||||
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
|
||||
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc genSection(d: PDoc, kind: TSymKind) =
|
||||
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
|
||||
case n.kind
|
||||
of nkCommentStmt:
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
let stripped = n.comment.substr(2).strip
|
||||
result = %{ "comment": %stripped }
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skProc)
|
||||
of nkMethodDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skMethod)
|
||||
of nkIteratorDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skIterator)
|
||||
of nkMacroDef:
|
||||
result = genJSONItem(d, n, n.sons[namePos], skMacro)
|
||||
of nkTemplateDef:
|
||||
result = genJSONItem(d, n, n.sons[namePos], skTemplate)
|
||||
of nkConverterDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
var elem = jArray
|
||||
if elem == nil: elem = newJArray()
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var r = generateJson(d, n.sons[i], elem)
|
||||
if r != nil:
|
||||
elem.add(r)
|
||||
if result == nil: result = elem
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
|
||||
discard generateJson(d, lastSon(n.sons[0]), jArray)
|
||||
else: discard
|
||||
|
||||
proc genSection(d: PDoc, kind: TSymKind) =
|
||||
const sectionNames: array[skModule..skTemplate, string] = [
|
||||
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
|
||||
"Iterators", "Converters", "Macros", "Templates"
|
||||
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
|
||||
"Iterators", "Iterators", "Converters", "Macros", "Templates"
|
||||
]
|
||||
if d.section[kind] == nil: return
|
||||
if d.section[kind] == nil: return
|
||||
var title = sectionNames[kind].toRope
|
||||
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
@@ -313,7 +527,7 @@ proc genSection(d: PDoc, kind: TSymKind) =
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
|
||||
|
||||
proc genOutFile(d: PDoc): PRope =
|
||||
proc genOutFile(d: PDoc): PRope =
|
||||
var
|
||||
code, content: PRope
|
||||
title = ""
|
||||
@@ -321,7 +535,7 @@ proc genOutFile(d: PDoc): PRope =
|
||||
var tmp = ""
|
||||
renderTocEntries(d[], j, 1, tmp)
|
||||
var toc = tmp.toRope
|
||||
for i in countup(low(TSymKind), high(TSymKind)):
|
||||
for i in countup(low(TSymKind), high(TSymKind)):
|
||||
genSection(d, i)
|
||||
app(toc, d.toc[i])
|
||||
if toc != nil:
|
||||
@@ -329,46 +543,46 @@ proc genOutFile(d: PDoc): PRope =
|
||||
for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
|
||||
if d.meta[metaTitle].len != 0: title = d.meta[metaTitle]
|
||||
else: title = "Module " & extractFilename(changeFileExt(d.filename, ""))
|
||||
|
||||
|
||||
let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
|
||||
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
|
||||
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time", "content"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), code])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
|
||||
d.meta[metaVersion].toRope])
|
||||
else:
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
|
||||
proc generateIndex*(d: PDoc) =
|
||||
if optGenIndex in gGlobalOptions:
|
||||
writeIndexFile(d[], splitFile(options.outFile).dir /
|
||||
splitFile(d.filename).name & indexExt)
|
||||
writeIndexFile(d[], splitFile(options.outFile).dir /
|
||||
splitFile(d.filename).name & IndexExt)
|
||||
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
var content = genOutFile(d)
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
writeRope(content, getOutFile(filename, outExt), useWarning)
|
||||
|
||||
proc CommandDoc*() =
|
||||
proc commandDoc*() =
|
||||
var ast = parseFile(gProjectMainIdx)
|
||||
if ast == nil: return
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
d.hasToc = true
|
||||
generateDoc(d, ast)
|
||||
writeOutput(d, gProjectFull, HtmlExt)
|
||||
generateIndex(d)
|
||||
|
||||
proc CommandRstAux(filename, outExt: string) =
|
||||
proc commandRstAux(filename, outExt: string) =
|
||||
var filen = addFileExt(filename, "txt")
|
||||
var d = newDocumentor(filen, options.gConfigVars)
|
||||
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
|
||||
@@ -381,19 +595,33 @@ proc CommandRstAux(filename, outExt: string) =
|
||||
writeOutput(d, filename, outExt)
|
||||
generateIndex(d)
|
||||
|
||||
proc CommandRst2Html*() =
|
||||
CommandRstAux(gProjectFull, HtmlExt)
|
||||
proc commandRst2Html*() =
|
||||
commandRstAux(gProjectFull, HtmlExt)
|
||||
|
||||
proc CommandRst2TeX*() =
|
||||
proc commandRst2TeX*() =
|
||||
splitter = "\\-"
|
||||
CommandRstAux(gProjectFull, TexExt)
|
||||
commandRstAux(gProjectFull, TexExt)
|
||||
|
||||
proc CommandBuildIndex*() =
|
||||
proc commandJSON*() =
|
||||
var ast = parseFile(gProjectMainIdx)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
d.hasToc = true
|
||||
var json = generateJson(d, ast)
|
||||
var content = newRope(pretty(json))
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
echo getOutFile(gProjectFull, JsonExt)
|
||||
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
||||
|
||||
proc commandBuildIndex*() =
|
||||
var content = mergeIndexes(gProjectFull).toRope
|
||||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
["Index".toRope, nil, nil, toRope(getDateStr()),
|
||||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
["Index".toRope, nil, nil, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, nil, nil])
|
||||
writeRope(code, getOutFile("theindex", HtmlExt))
|
||||
|
||||
@@ -27,7 +27,7 @@ proc close(p: PPassContext, n: PNode): PNode =
|
||||
try:
|
||||
generateIndex(g.doc)
|
||||
except EIO:
|
||||
nil
|
||||
discard
|
||||
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -46,4 +46,4 @@ proc myOpen(module: PSym): PPassContext =
|
||||
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
|
||||
|
||||
proc finishDoc2Pass*(project: string) =
|
||||
nil
|
||||
discard
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This file implements the FFI part of the evaluator for Nimrod code.
|
||||
|
||||
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs
|
||||
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
|
||||
|
||||
when defined(windows):
|
||||
const libcDll = "msvcrt.dll"
|
||||
@@ -20,7 +20,11 @@ type
|
||||
TDllCache = tables.TTable[string, TLibHandle]
|
||||
var
|
||||
gDllCache = initTable[string, TLibHandle]()
|
||||
gExeHandle = LoadLib()
|
||||
|
||||
when defined(windows):
|
||||
var gExeHandle = loadLib(os.getAppFilename())
|
||||
else:
|
||||
var gExeHandle = loadLib()
|
||||
|
||||
proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
|
||||
result = cache[dll]
|
||||
@@ -28,15 +32,17 @@ proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
|
||||
var libs: seq[string] = @[]
|
||||
libCandidates(dll, libs)
|
||||
for c in libs:
|
||||
result = LoadLib(c)
|
||||
result = loadLib(c)
|
||||
if not result.isNil: break
|
||||
if result.isNil:
|
||||
GlobalError(info, "cannot load: " & dll)
|
||||
globalError(info, "cannot load: " & dll)
|
||||
cache[dll] = result
|
||||
|
||||
const
|
||||
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
|
||||
|
||||
var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable
|
||||
|
||||
proc importcSymbol*(sym: PSym): PNode =
|
||||
let name = ropeToStr(sym.loc.r)
|
||||
|
||||
@@ -47,10 +53,11 @@ proc importcSymbol*(sym: PSym): PNode =
|
||||
of "stdin": result.intVal = cast[TAddress](system.stdin)
|
||||
of "stdout": result.intVal = cast[TAddress](system.stdout)
|
||||
of "stderr": result.intVal = cast[TAddress](system.stderr)
|
||||
of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno)
|
||||
else:
|
||||
let lib = sym.annex
|
||||
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
GlobalError(sym.info, "dynlib needs to be a string lit for the REPL")
|
||||
globalError(sym.info, "dynlib needs to be a string lit for the REPL")
|
||||
var theAddr: pointer
|
||||
if lib.isNil and not gExehandle.isNil:
|
||||
# first try this exe itself:
|
||||
@@ -58,10 +65,12 @@ proc importcSymbol*(sym: PSym): PNode =
|
||||
# then try libc:
|
||||
if theAddr.isNil:
|
||||
let dllhandle = gDllCache.getDll(libcDll, sym.info)
|
||||
theAddr = dllhandle.checkedSymAddr(name)
|
||||
else:
|
||||
let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
|
||||
theAddr = dllhandle.checkedSymAddr(name)
|
||||
theAddr = dllhandle.symAddr(name)
|
||||
elif not lib.isNil:
|
||||
let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll
|
||||
else: lib.path.strVal, sym.info)
|
||||
theAddr = dllhandle.symAddr(name)
|
||||
if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
|
||||
result.intVal = cast[TAddress](theAddr)
|
||||
|
||||
proc mapType(t: ast.PType): ptr libffi.TType =
|
||||
@@ -78,7 +87,7 @@ proc mapType(t: ast.PType): ptr libffi.TType =
|
||||
of tyFloat, tyFloat64: result = addr libffi.type_double
|
||||
of tyFloat32: result = addr libffi.type_float
|
||||
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
|
||||
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil:
|
||||
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyStatic, tyNil:
|
||||
result = addr libffi.type_pointer
|
||||
of tyDistinct:
|
||||
result = mapType(t.sons[0])
|
||||
@@ -93,7 +102,7 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
|
||||
of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
|
||||
of ccCDecl: result = DEFAULT_ABI
|
||||
else:
|
||||
GlobalError(info, "cannot map calling convention to FFI")
|
||||
globalError(info, "cannot map calling convention to FFI")
|
||||
|
||||
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
|
||||
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
|
||||
@@ -107,7 +116,7 @@ proc packSize(v: PNode, typ: PType): int =
|
||||
if v.kind in {nkNilLit, nkPtrLit}:
|
||||
result = sizeof(pointer)
|
||||
else:
|
||||
result = sizeof(pointer) + packSize(v.sons[0], typ.sons[0])
|
||||
result = sizeof(pointer) + packSize(v.sons[0], typ.lastSon)
|
||||
of tyDistinct, tyGenericInst:
|
||||
result = packSize(v, typ.sons[0])
|
||||
of tyArray, tyArrayConstr:
|
||||
@@ -139,10 +148,10 @@ proc getField(n: PNode; position: int): PSym =
|
||||
else: internalError(n.info, "getField(record case branch)")
|
||||
of nkSym:
|
||||
if n.sym.position == position: result = n.sym
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc packObject(x: PNode, typ: PType, res: pointer) =
|
||||
InternalAssert x.kind in {nkObjConstr, nkPar}
|
||||
internalAssert x.kind in {nkObjConstr, nkPar}
|
||||
# compute the field's offsets:
|
||||
discard typ.getSize
|
||||
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
|
||||
@@ -155,7 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
|
||||
let field = getField(typ.n, i)
|
||||
pack(it, field.typ, res +! field.offset)
|
||||
else:
|
||||
GlobalError(x.info, "cannot pack unnamed tuple")
|
||||
globalError(x.info, "cannot pack unnamed tuple")
|
||||
|
||||
const maxPackDepth = 20
|
||||
var packRecCheck = 0
|
||||
@@ -184,7 +193,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
|
||||
of 4: awr(int32, v.intVal.int32)
|
||||
of 8: awr(int64, v.intVal.int64)
|
||||
else:
|
||||
GlobalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
|
||||
globalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
|
||||
of tyFloat: awr(float, v.floatVal)
|
||||
of tyFloat32: awr(float32, v.floatVal)
|
||||
of tyFloat64: awr(float64, v.floatVal)
|
||||
@@ -192,25 +201,25 @@ proc pack(v: PNode, typ: PType, res: pointer) =
|
||||
of tyPointer, tyProc, tyCString, tyString:
|
||||
if v.kind == nkNilLit:
|
||||
# nothing to do since the memory is 0 initialized anyway
|
||||
nil
|
||||
discard
|
||||
elif v.kind == nkPtrLit:
|
||||
awr(pointer, cast[pointer](v.intVal))
|
||||
elif v.kind in {nkStrLit..nkTripleStrLit}:
|
||||
awr(cstring, cstring(v.strVal))
|
||||
else:
|
||||
GlobalError(v.info, "cannot map pointer/proc value to FFI")
|
||||
globalError(v.info, "cannot map pointer/proc value to FFI")
|
||||
of tyPtr, tyRef, tyVar:
|
||||
if v.kind == nkNilLit:
|
||||
# nothing to do since the memory is 0 initialized anyway
|
||||
nil
|
||||
discard
|
||||
elif v.kind == nkPtrLit:
|
||||
awr(pointer, cast[pointer](v.intVal))
|
||||
else:
|
||||
if packRecCheck > maxPackDepth:
|
||||
packRecCheck = 0
|
||||
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
|
||||
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
|
||||
inc packRecCheck
|
||||
pack(v.sons[0], typ.sons[0], res +! sizeof(pointer))
|
||||
pack(v.sons[0], typ.lastSon, res +! sizeof(pointer))
|
||||
dec packRecCheck
|
||||
awr(pointer, res +! sizeof(pointer))
|
||||
of tyArray, tyArrayConstr:
|
||||
@@ -220,11 +229,11 @@ proc pack(v: PNode, typ: PType, res: pointer) =
|
||||
of tyObject, tyTuple:
|
||||
packObject(v, typ, res)
|
||||
of tyNil:
|
||||
nil
|
||||
discard
|
||||
of tyDistinct, tyGenericInst:
|
||||
pack(v, typ.sons[0], res)
|
||||
else:
|
||||
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
|
||||
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
|
||||
|
||||
proc unpack(x: pointer, typ: PType, n: PNode): PNode
|
||||
|
||||
@@ -234,14 +243,14 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
unpackObjectAdd(x, n.sons[i], result)
|
||||
of nkRecCase:
|
||||
GlobalError(result.info, "case objects cannot be unpacked")
|
||||
globalError(result.info, "case objects cannot be unpacked")
|
||||
of nkSym:
|
||||
var pair = newNodeI(nkExprColonExpr, result.info, 2)
|
||||
pair.sons[0] = n
|
||||
pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
|
||||
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
|
||||
result.add pair
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
|
||||
# compute the field's offsets:
|
||||
@@ -253,14 +262,14 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
|
||||
result = newNode(nkPar)
|
||||
result.typ = typ
|
||||
if typ.n.isNil:
|
||||
InternalError("cannot unpack unnamed tuple")
|
||||
internalError("cannot unpack unnamed tuple")
|
||||
unpackObjectAdd(x, typ.n, result)
|
||||
else:
|
||||
result = n
|
||||
if result.kind notin {nkObjConstr, nkPar}:
|
||||
GlobalError(n.info, "cannot map value from FFI")
|
||||
globalError(n.info, "cannot map value from FFI")
|
||||
if typ.n.isNil:
|
||||
GlobalError(n.info, "cannot unpack unnamed tuple")
|
||||
globalError(n.info, "cannot unpack unnamed tuple")
|
||||
for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkExprColonExpr:
|
||||
@@ -279,7 +288,7 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
|
||||
else:
|
||||
result = n
|
||||
if result.kind != nkBracket:
|
||||
GlobalError(n.info, "cannot map value from FFI")
|
||||
globalError(n.info, "cannot map value from FFI")
|
||||
let baseSize = typ.sons[1].getSize
|
||||
for i in 0 .. < result.len:
|
||||
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
|
||||
@@ -303,7 +312,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
#echo "expected ", k, " but got ", result.kind
|
||||
#debug result
|
||||
return newNodeI(nkExceptBranch, n.info)
|
||||
#GlobalError(n.info, "cannot map value from FFI")
|
||||
#globalError(n.info, "cannot map value from FFI")
|
||||
result.field = v
|
||||
|
||||
template setNil() =
|
||||
@@ -328,19 +337,19 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
of tyInt16: awi(nkInt16Lit, rd(int16, x))
|
||||
of tyInt32: awi(nkInt32Lit, rd(int32, x))
|
||||
of tyInt64: awi(nkInt64Lit, rd(int64, x))
|
||||
of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
|
||||
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
|
||||
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
|
||||
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
|
||||
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
|
||||
of tyUInt: awi(nkUIntLit, rd(uint, x).BiggestInt)
|
||||
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).BiggestInt)
|
||||
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).BiggestInt)
|
||||
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).BiggestInt)
|
||||
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).BiggestInt)
|
||||
of tyEnum:
|
||||
case typ.getSize
|
||||
of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
|
||||
of 2: awi(nkIntLit, rd(uint16, x).biggestInt)
|
||||
of 4: awi(nkIntLit, rd(int32, x).biggestInt)
|
||||
of 8: awi(nkIntLit, rd(int64, x).biggestInt)
|
||||
of 1: awi(nkIntLit, rd(uint8, x).BiggestInt)
|
||||
of 2: awi(nkIntLit, rd(uint16, x).BiggestInt)
|
||||
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
|
||||
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
|
||||
else:
|
||||
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
|
||||
globalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
|
||||
of tyFloat: awf(nkFloatLit, rd(float, x))
|
||||
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
|
||||
of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
|
||||
@@ -362,10 +371,10 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
awi(nkPtrLit, cast[TAddress](p))
|
||||
elif n != nil and n.len == 1:
|
||||
internalAssert n.kind == nkRefTy
|
||||
n.sons[0] = unpack(p, typ.sons[0], n.sons[0])
|
||||
n.sons[0] = unpack(p, typ.lastSon, n.sons[0])
|
||||
result = n
|
||||
else:
|
||||
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
of tyObject, tyTuple:
|
||||
result = unpackObject(x, typ, n)
|
||||
of tyArray, tyArrayConstr:
|
||||
@@ -382,7 +391,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
result = unpack(x, typ.sons[0], n)
|
||||
else:
|
||||
# XXX what to do with 'array' here?
|
||||
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
|
||||
proc fficast*(x: PNode, destTyp: PType): PNode =
|
||||
if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer,
|
||||
@@ -405,7 +414,7 @@ proc fficast*(x: PNode, destTyp: PType): PNode =
|
||||
dealloc a
|
||||
|
||||
proc callForeignFunction*(call: PNode): PNode =
|
||||
InternalAssert call.sons[0].kind == nkPtrLit
|
||||
internalAssert call.sons[0].kind == nkPtrLit
|
||||
|
||||
var cif: TCif
|
||||
var sig: TParamList
|
||||
@@ -413,12 +422,12 @@ proc callForeignFunction*(call: PNode): PNode =
|
||||
for i in 1..call.len-1:
|
||||
sig[i-1] = mapType(call.sons[i].typ)
|
||||
if sig[i-1].isNil:
|
||||
GlobalError(call.info, "cannot map FFI type")
|
||||
globalError(call.info, "cannot map FFI type")
|
||||
|
||||
let typ = call.sons[0].typ
|
||||
if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
|
||||
mapType(typ.sons[0]), sig) != OK:
|
||||
GlobalError(call.info, "error in FFI call")
|
||||
globalError(call.info, "error in FFI call")
|
||||
|
||||
var args: TArgList
|
||||
let fn = cast[pointer](call.sons[0].intVal)
|
||||
@@ -441,3 +450,46 @@ proc callForeignFunction*(call: PNode): PNode =
|
||||
for i in 1 .. call.len-1:
|
||||
call.sons[i] = unpack(args[i-1], typ.sons[i], call[i])
|
||||
dealloc args[i-1]
|
||||
|
||||
proc callForeignFunction*(fn: PNode, fntyp: PType,
|
||||
args: var TNodeSeq, start, len: int,
|
||||
info: TLineInfo): PNode =
|
||||
internalAssert fn.kind == nkPtrLit
|
||||
|
||||
var cif: TCif
|
||||
var sig: TParamList
|
||||
for i in 0..len-1:
|
||||
var aTyp = args[i+start].typ
|
||||
if aTyp.isNil:
|
||||
internalAssert i+1 < fntyp.len
|
||||
aTyp = fntyp.sons[i+1]
|
||||
args[i+start].typ = aTyp
|
||||
sig[i] = mapType(aTyp)
|
||||
if sig[i].isNil: globalError(info, "cannot map FFI type")
|
||||
|
||||
if prep_cif(cif, mapCallConv(fntyp.callConv, info), cuint(len),
|
||||
mapType(fntyp.sons[0]), sig) != OK:
|
||||
globalError(info, "error in FFI call")
|
||||
|
||||
var cargs: TArgList
|
||||
let fn = cast[pointer](fn.intVal)
|
||||
for i in 0 .. len-1:
|
||||
let t = args[i+start].typ
|
||||
cargs[i] = alloc0(packSize(args[i+start], t))
|
||||
pack(args[i+start], t, cargs[i])
|
||||
let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
|
||||
else: alloc(fntyp.sons[0].getSize.int)
|
||||
|
||||
libffi.call(cif, fn, retVal, cargs)
|
||||
|
||||
if retVal.isNil:
|
||||
result = emptyNode
|
||||
else:
|
||||
result = unpack(retVal, fntyp.sons[0], nil)
|
||||
result.info = info
|
||||
|
||||
if retVal != nil: dealloc retVal
|
||||
for i in 0 .. len-1:
|
||||
let t = args[i+start].typ
|
||||
args[i+start] = unpack(cargs[i], t, args[i+start])
|
||||
dealloc cargs[i]
|
||||
|
||||
@@ -23,12 +23,12 @@ when hasFFI:
|
||||
|
||||
type
|
||||
PStackFrame* = ref TStackFrame
|
||||
TStackFrame*{.final.} = object
|
||||
mapping*: TIdNodeTable # mapping from symbols to nodes
|
||||
prc*: PSym # current prc; proc that is evaluated
|
||||
call*: PNode
|
||||
next*: PStackFrame # for stacking
|
||||
params*: TNodeSeq # parameters passed to the proc
|
||||
TStackFrame* = object
|
||||
prc: PSym # current prc; proc that is evaluated
|
||||
slots: TNodeSeq # parameters passed to the proc + locals;
|
||||
# parameters come first
|
||||
call: PNode
|
||||
next: PStackFrame # for stacking
|
||||
|
||||
TEvalMode* = enum ## reason for evaluation
|
||||
emRepl, ## evaluate because in REPL mode
|
||||
@@ -53,7 +53,8 @@ type
|
||||
features: TSandboxFlags
|
||||
globals*: TIdNodeTable # state of global vars
|
||||
getType*: proc(n: PNode): PNode {.closure.}
|
||||
|
||||
handleIsOperator*: proc(n: PNode): PNode {.closure.}
|
||||
|
||||
PEvalContext* = ref TEvalContext
|
||||
|
||||
TEvalFlag = enum
|
||||
@@ -67,10 +68,9 @@ const
|
||||
# other idea: use a timeout! -> Wether code compiles depends on the machine
|
||||
# the compiler runs on then! Bad idea!
|
||||
|
||||
proc newStackFrame*(): PStackFrame =
|
||||
proc newStackFrame*(): PStackFrame =
|
||||
new(result)
|
||||
initIdNodeTable(result.mapping)
|
||||
result.params = @[]
|
||||
result.slots = @[]
|
||||
|
||||
proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
|
||||
new(result)
|
||||
@@ -91,6 +91,7 @@ proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
|
||||
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
|
||||
|
||||
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
|
||||
if defined(debug) and gVerbosity >= 3: writeStackTrace()
|
||||
result = newNodeI(nkExceptBranch, info)
|
||||
# creating a nkExceptBranch without sons
|
||||
# means that it could not be evaluated
|
||||
@@ -111,13 +112,18 @@ proc stackTraceAux(x: PStackFrame) =
|
||||
add(s, x.prc.name.s)
|
||||
MsgWriteln(s)
|
||||
|
||||
proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg = "") =
|
||||
proc stackTrace(c: PEvalContext, info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
MsgWriteln("stack trace: (most recent call last)")
|
||||
stackTraceAux(c.tos)
|
||||
LocalError(n.info, msg, arg)
|
||||
LocalError(info, msg, arg)
|
||||
|
||||
proc isSpecial(n: PNode): bool {.inline.} =
|
||||
result = n.kind == nkExceptBranch
|
||||
template isSpecial(n: PNode): bool = n.kind == nkExceptBranch
|
||||
template bailout() {.dirty.} =
|
||||
if isSpecial(result): return
|
||||
|
||||
template evalX(n, flags) {.dirty.} =
|
||||
result = evalAux(c, n, flags)
|
||||
bailout()
|
||||
|
||||
proc myreset(n: PNode) =
|
||||
when defined(system.reset):
|
||||
@@ -129,19 +135,17 @@ proc evalIf(c: PEvalContext, n: PNode): PNode =
|
||||
var i = 0
|
||||
var length = sonsLen(n)
|
||||
while (i < length) and (sonsLen(n.sons[i]) >= 2):
|
||||
result = evalAux(c, n.sons[i].sons[0], {})
|
||||
if isSpecial(result): return
|
||||
if (result.kind == nkIntLit) and (result.intVal != 0):
|
||||
evalX(n.sons[i].sons[0], {})
|
||||
if result.kind == nkIntLit and result.intVal != 0:
|
||||
return evalAux(c, n.sons[i].sons[1], {})
|
||||
inc(i)
|
||||
if (i < length) and (sonsLen(n.sons[i]) < 2):
|
||||
if (i < length) and (sonsLen(n.sons[i]) < 2):
|
||||
result = evalAux(c, n.sons[i].sons[0], {})
|
||||
else:
|
||||
else:
|
||||
result = emptyNode
|
||||
|
||||
proc evalCase(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[0], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], {})
|
||||
var res = result
|
||||
result = emptyNode
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
@@ -159,11 +163,11 @@ var
|
||||
gNestedEvals: int # count the recursive calls to ``evalAux`` to prevent
|
||||
# endless recursion
|
||||
|
||||
proc evalWhile(c: PEvalContext, n: PNode): PNode =
|
||||
while true:
|
||||
result = evalAux(c, n.sons[0], {})
|
||||
if isSpecial(result): return
|
||||
if getOrdValue(result) == 0: break
|
||||
proc evalWhile(c: PEvalContext, n: PNode): PNode =
|
||||
while true:
|
||||
evalX(n.sons[0], {})
|
||||
if getOrdValue(result) == 0:
|
||||
result = emptyNode; break
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
case result.kind
|
||||
of nkBreakStmt:
|
||||
@@ -178,7 +182,7 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
|
||||
if allowInfiniteLoops in c.features:
|
||||
gWhileCounter = 0
|
||||
else:
|
||||
stackTrace(c, n, errTooManyIterations)
|
||||
stackTrace(c, n.info, errTooManyIterations)
|
||||
break
|
||||
|
||||
proc evalBlock(c: PEvalContext, n: PNode): PNode =
|
||||
@@ -223,7 +227,9 @@ proc evalTry(c: PEvalContext, n: PNode): PNode =
|
||||
else:
|
||||
for j in countup(0, blen - 2):
|
||||
assert(n.sons[i].sons[j].kind == nkType)
|
||||
if exc.typ.id == n.sons[i].sons[j].typ.id:
|
||||
let a = exc.typ.skipTypes(abstractPtrs)
|
||||
let b = n.sons[i].sons[j].typ.skipTypes(abstractPtrs)
|
||||
if a == b:
|
||||
result = evalAux(c, n.sons[i].sons[blen - 1], {})
|
||||
exc = result
|
||||
break
|
||||
@@ -240,7 +246,7 @@ proc getNullValueAux(obj: PNode, result: PNode) =
|
||||
getNullValueAux(obj.sons[0], result)
|
||||
for i in countup(1, sonsLen(obj) - 1):
|
||||
getNullValueAux(lastSon(obj.sons[i]), result)
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
var s = obj.sym
|
||||
var p = newNodeIT(nkExprColonExpr, result.info, s.typ)
|
||||
addSon(p, newSymNode(s, result.info))
|
||||
@@ -258,8 +264,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkUIntLit, info, t)
|
||||
of tyFloat..tyFloat128:
|
||||
result = newNodeIt(nkFloatLit, info, t)
|
||||
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
|
||||
tyStmt, tyTypeDesc, tyProc:
|
||||
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
|
||||
tyStmt, tyTypeDesc, tyStatic, tyProc:
|
||||
result = newNodeIT(nkNilLit, info, t)
|
||||
of tyObject:
|
||||
result = newNodeIT(nkPar, info, t)
|
||||
@@ -287,67 +293,93 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkCurly, info, t)
|
||||
else: InternalError("getNullValue: " & $t.kind)
|
||||
|
||||
proc evalVar(c: PEvalContext, n: PNode): PNode =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind != nkIdentDefs: return raiseCannotEval(c, n.info)
|
||||
# XXX var (x, y) = z support?
|
||||
proc evalVarValue(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n, {})
|
||||
if result.kind in {nkType..nkNilLit}: result = result.copyNode
|
||||
|
||||
proc allocSlot(c: PStackFrame; sym: PSym): int =
|
||||
result = sym.position + ord(sym.kind == skParam)
|
||||
if result == 0 and sym.kind != skResult:
|
||||
result = c.slots.len
|
||||
if result == 0: result = 1
|
||||
sym.position = result
|
||||
setLen(c.slots, max(result+1, c.slots.len))
|
||||
|
||||
proc setSlot(c: PStackFrame, sym: PSym, val: PNode) =
|
||||
assert sym.owner == c.prc or sfFromGeneric in sym.flags
|
||||
let idx = allocSlot(c, sym)
|
||||
c.slots[idx] = val
|
||||
|
||||
proc setVar(c: PEvalContext, v: PSym, n: PNode) =
|
||||
if sfGlobal notin v.flags: setSlot(c.tos, v, n)
|
||||
else: IdNodeTablePut(c.globals, v, n)
|
||||
|
||||
proc evalVar(c: PEvalContext, n: PNode): PNode =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
#assert(a.sons[0].kind == nkSym) can happen for transformed vars
|
||||
if a.sons[2].kind != nkEmpty:
|
||||
result = evalAux(c, a.sons[2], {})
|
||||
if result.kind in {nkType..nkNilLit}:
|
||||
if a.kind == nkVarTuple:
|
||||
result = evalVarValue(c, a.lastSon)
|
||||
if result.kind in {nkType..nkNilLit}:
|
||||
result = result.copyNode
|
||||
if isSpecial(result): return
|
||||
bailout()
|
||||
if result.kind != nkPar:
|
||||
return raiseCannotEval(c, n.info)
|
||||
for i in 0 .. a.len-3:
|
||||
var v = a.sons[i].sym
|
||||
setVar(c, v, result.sons[i])
|
||||
else:
|
||||
result = getNullValue(a.sons[0].typ, a.sons[0].info)
|
||||
if a.sons[0].kind == nkSym:
|
||||
var v = a.sons[0].sym
|
||||
IdNodeTablePut(c.tos.mapping, v, result)
|
||||
else:
|
||||
# assign to a.sons[0]:
|
||||
var x = result
|
||||
result = evalAux(c, a.sons[0], {})
|
||||
if isSpecial(result): return
|
||||
myreset(x)
|
||||
x.kind = result.kind
|
||||
x.typ = result.typ
|
||||
case x.kind
|
||||
of nkCharLit..nkInt64Lit: x.intVal = result.intVal
|
||||
of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
|
||||
of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
|
||||
of nkIdent: x.ident = result.ident
|
||||
of nkSym: x.sym = result.sym
|
||||
if a.sons[2].kind != nkEmpty:
|
||||
result = evalVarValue(c, a.sons[2])
|
||||
bailout()
|
||||
else:
|
||||
if x.kind notin {nkEmpty..nkNilLit}:
|
||||
discardSons(x)
|
||||
for j in countup(0, sonsLen(result) - 1): addSon(x, result.sons[j])
|
||||
result = getNullValue(a.sons[0].typ, a.sons[0].info)
|
||||
if a.sons[0].kind == nkSym:
|
||||
var v = a.sons[0].sym
|
||||
setVar(c, v, result)
|
||||
else:
|
||||
# assign to a.sons[0]:
|
||||
var x = result
|
||||
evalX(a.sons[0], {})
|
||||
myreset(x)
|
||||
x.kind = result.kind
|
||||
x.typ = result.typ
|
||||
case x.kind
|
||||
of nkCharLit..nkInt64Lit: x.intVal = result.intVal
|
||||
of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
|
||||
of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
|
||||
of nkIdent: x.ident = result.ident
|
||||
of nkSym: x.sym = result.sym
|
||||
else:
|
||||
if x.kind notin {nkEmpty..nkNilLit}:
|
||||
discardSons(x)
|
||||
for j in countup(0, sonsLen(result) - 1): addSon(x, result.sons[j])
|
||||
result = emptyNode
|
||||
|
||||
proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
|
||||
result = efLValue in flags or n.typ == nil or
|
||||
n.typ.kind in {tyExpr, tyStmt, tyTypeDesc}
|
||||
n.typ.kind in {tyExpr, tyStatic, tyStmt, tyTypeDesc}
|
||||
|
||||
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
|
||||
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
|
||||
# We need to return a node to the actual value,
|
||||
# which can be modified.
|
||||
assert sym.position != 0 or skResult == sym.kind
|
||||
var x = c
|
||||
while x != nil:
|
||||
if sym.kind == skResult and x.params.len > 0:
|
||||
result = x.params[0]
|
||||
if result == nil: result = emptyNode
|
||||
while x != nil:
|
||||
if sym.owner == x.prc:
|
||||
result = x.slots[sym.position]
|
||||
assert result != nil
|
||||
if not aliasNeeded(result, flags):
|
||||
result = copyTree(result)
|
||||
return
|
||||
result = IdNodeTableGet(x.mapping, sym)
|
||||
if result != nil and not aliasNeeded(result, flags):
|
||||
result = copyTree(result)
|
||||
if result != nil: return
|
||||
x = x.next
|
||||
#internalError(sym.info, "cannot eval " & sym.name.s)
|
||||
#internalError(sym.info, "cannot eval " & sym.name.s & " " & $sym.position)
|
||||
result = raiseCannotEval(nil, sym.info)
|
||||
#result = emptyNode
|
||||
|
||||
proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
|
||||
if sfCompileTime in s.flags or c.mode == emRepl:
|
||||
if sfCompileTime in s.flags or c.mode == emRepl or s.kind == skForVar:
|
||||
result = IdNodeTableGet(c.globals, s)
|
||||
if result != nil:
|
||||
if not aliasNeeded(result, flags):
|
||||
@@ -369,17 +401,19 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
|
||||
else:
|
||||
result = raiseCannotEval(nil, s.info)
|
||||
|
||||
proc optBody(c: PEvalContext, s: PSym): PNode =
|
||||
result = s.getBody
|
||||
|
||||
proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||
var d = newStackFrame()
|
||||
d.call = n
|
||||
var prc = n.sons[0]
|
||||
let isClosure = prc.kind == nkClosure
|
||||
setlen(d.params, sonsLen(n) + ord(isClosure))
|
||||
setlen(d.slots, sonsLen(n) + ord(isClosure))
|
||||
if isClosure:
|
||||
#debug prc
|
||||
result = evalAux(c, prc.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
d.params[sonsLen(n)] = result
|
||||
evalX(prc.sons[1], {efLValue})
|
||||
d.slots[sonsLen(n)] = result
|
||||
result = evalAux(c, prc.sons[0], {})
|
||||
else:
|
||||
result = evalAux(c, prc, {})
|
||||
@@ -395,47 +429,43 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||
InternalError(n.info, "evalCall")
|
||||
return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
result = evalAux(c, n.sons[i], {})
|
||||
if isSpecial(result): return
|
||||
d.params[i] = result
|
||||
if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
|
||||
evalX(n.sons[i], {})
|
||||
d.slots[i] = result
|
||||
if n.typ != nil: d.slots[0] = getNullValue(n.typ, n.info)
|
||||
|
||||
when hasFFI:
|
||||
if sfImportc in prc.sym.flags and allowFFI in c.features:
|
||||
var newCall = newNodeI(nkCall, n.info, n.len)
|
||||
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
||||
for i in 1 .. <n.len:
|
||||
newCall.sons[i] = d.params[i]
|
||||
newCall.sons[i] = d.slots[i]
|
||||
return callForeignFunction(newCall)
|
||||
|
||||
pushStackFrame(c, d)
|
||||
result = evalAux(c, prc.sym.getBody, {})
|
||||
if result.kind == nkExceptBranch: return
|
||||
if n.typ != nil: result = d.params[0]
|
||||
evalX(optBody(c, prc.sym), {})
|
||||
if n.typ != nil: result = d.slots[0]
|
||||
popStackFrame(c)
|
||||
|
||||
proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = evalAux(c, n.sons[0], flags)
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], flags)
|
||||
var x = result
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {})
|
||||
var idx = getOrdValue(result)
|
||||
result = emptyNode
|
||||
case x.kind
|
||||
of nkPar:
|
||||
of nkPar:
|
||||
if (idx >= 0) and (idx < sonsLen(x)):
|
||||
result = x.sons[int(idx)]
|
||||
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||
if not aliasNeeded(result, flags): result = copyTree(result)
|
||||
else:
|
||||
stackTrace(c, n, errIndexOutOfBounds)
|
||||
stackTrace(c, n.info, errIndexOutOfBounds)
|
||||
of nkBracket, nkMetaNode:
|
||||
if (idx >= 0) and (idx < sonsLen(x)):
|
||||
result = x.sons[int(idx)]
|
||||
if not aliasNeeded(result, flags): result = copyTree(result)
|
||||
else:
|
||||
stackTrace(c, n, errIndexOutOfBounds)
|
||||
stackTrace(c, n.info, errIndexOutOfBounds)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if efLValue in flags: return raiseCannotEval(c, n.info)
|
||||
result = newNodeIT(nkCharLit, x.info, getSysType(tyChar))
|
||||
@@ -444,14 +474,13 @@ proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
elif idx == len(x.strVal):
|
||||
nil
|
||||
else:
|
||||
stackTrace(c, n, errIndexOutOfBounds)
|
||||
else: stackTrace(c, n, errNilAccess)
|
||||
stackTrace(c, n.info, errIndexOutOfBounds)
|
||||
else: stackTrace(c, n.info, errNilAccess)
|
||||
|
||||
proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
# a real field access; proc calls have already been transformed
|
||||
# XXX: field checks!
|
||||
result = evalAux(c, n.sons[0], flags)
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], flags)
|
||||
var x = result
|
||||
if x.kind != nkPar: return raiseCannotEval(c, n.info)
|
||||
# this is performance critical:
|
||||
@@ -459,48 +488,26 @@ proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = x.sons[field.position]
|
||||
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||
if not aliasNeeded(result, flags): result = copyTree(result)
|
||||
when false:
|
||||
var field = n.sons[1].sym
|
||||
for i in countup(0, sonsLen(x) - 1):
|
||||
var it = x.sons[i]
|
||||
if it.kind != nkExprColonExpr:
|
||||
# lookup per index:
|
||||
result = x.sons[field.position]
|
||||
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||
if not aliasNeeded(result, flags): result = copyTree(result)
|
||||
return
|
||||
#InternalError(it.info, "evalFieldAccess")
|
||||
if it.sons[0].sym.name.id == field.name.id:
|
||||
result = x.sons[i].sons[1]
|
||||
if not aliasNeeded(result, flags): result = copyTree(result)
|
||||
return
|
||||
stackTrace(c, n, errFieldXNotFound, field.name.s)
|
||||
result = emptyNode
|
||||
|
||||
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
|
||||
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
|
||||
var a = n.sons[0]
|
||||
if a.kind == nkBracketExpr and a.sons[0].typ.kind in {tyString, tyCString}:
|
||||
result = evalAux(c, a.sons[0], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(a.sons[0], {efLValue})
|
||||
var x = result
|
||||
result = evalAux(c, a.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
evalX(a.sons[1], {})
|
||||
var idx = getOrdValue(result)
|
||||
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
if result.kind != nkCharLit: return raiseCannotEval(c, n.info)
|
||||
evalX(n.sons[1], {})
|
||||
if result.kind notin {nkIntLit, nkCharLit}: return c.raiseCannotEval(n.info)
|
||||
|
||||
if (idx >= 0) and (idx < len(x.strVal)):
|
||||
if idx >= 0 and idx < len(x.strVal):
|
||||
x.strVal[int(idx)] = chr(int(result.intVal))
|
||||
else:
|
||||
stackTrace(c, n, errIndexOutOfBounds)
|
||||
else:
|
||||
stackTrace(c, n.info, errIndexOutOfBounds)
|
||||
else:
|
||||
result = evalAux(c, n.sons[0], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], {efLValue})
|
||||
var x = result
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {})
|
||||
myreset(x)
|
||||
x.kind = result.kind
|
||||
x.typ = result.typ
|
||||
@@ -518,13 +525,11 @@ proc evalAsgn(c: PEvalContext, n: PNode): PNode =
|
||||
assert result.kind == nkEmpty
|
||||
|
||||
proc evalSwap(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[0], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], {efLValue})
|
||||
var x = result
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {efLValue})
|
||||
if x.kind != result.kind:
|
||||
stackTrace(c, n, errCannotInterpretNodeX, $n.kind)
|
||||
stackTrace(c, n.info, errCannotInterpretNodeX, $n.kind)
|
||||
else:
|
||||
case x.kind
|
||||
of nkCharLit..nkInt64Lit: swap(x.intVal, result.intVal)
|
||||
@@ -553,8 +558,8 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = evalGlobalVar(c, s, flags)
|
||||
of skParam:
|
||||
# XXX what about LValue?
|
||||
if s.position + 1 <% c.tos.params.len:
|
||||
result = c.tos.params[s.position + 1]
|
||||
if s.position + 1 <% c.tos.slots.len:
|
||||
result = c.tos.slots[s.position + 1]
|
||||
of skConst: result = s.ast
|
||||
of skEnumField: result = newIntNodeT(s.position, n)
|
||||
else: result = nil
|
||||
@@ -564,11 +569,9 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {efLValue})
|
||||
var a = result
|
||||
result = evalAux(c, n.sons[2], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[2], {})
|
||||
var b = result
|
||||
case a.kind
|
||||
of nkCharLit..nkInt64Lit: a.intval = a.intVal + sign * getOrdValue(b)
|
||||
@@ -584,64 +587,62 @@ proc getStrValue(n: PNode): string =
|
||||
|
||||
proc evalEcho(c: PEvalContext, n: PNode): PNode =
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
result = evalAux(c, n.sons[i], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[i], {})
|
||||
Write(stdout, getStrValue(result))
|
||||
writeln(stdout, "")
|
||||
result = emptyNode
|
||||
|
||||
proc evalExit(c: PEvalContext, n: PNode): PNode =
|
||||
if c.mode in {emRepl, emStatic}:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {})
|
||||
Message(n.info, hintQuitCalled)
|
||||
quit(int(getOrdValue(result)))
|
||||
else:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
proc evalOr(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
if result.kind != nkIntLit: InternalError(n.info, "evalOr")
|
||||
elif result.intVal == 0: result = evalAux(c, n.sons[2], {})
|
||||
evalX(n.sons[1], {})
|
||||
if result.intVal == 0: result = evalAux(c, n.sons[2], {})
|
||||
|
||||
proc evalAnd(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
if result.kind != nkIntLit: InternalError(n.info, "evalAnd")
|
||||
elif result.intVal != 0: result = evalAux(c, n.sons[2], {})
|
||||
evalX(n.sons[1], {})
|
||||
if result.intVal != 0: result = evalAux(c, n.sons[2], {})
|
||||
|
||||
proc evalNew(c: PEvalContext, n: PNode): PNode =
|
||||
#if c.mode == emOptimize: return raiseCannotEval(c, n.info)
|
||||
|
||||
# we ignore the finalizer for now and most likely forever :-)
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {efLValue})
|
||||
var a = result
|
||||
var t = skipTypes(n.sons[1].typ, abstractVar)
|
||||
if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
|
||||
myreset(a)
|
||||
a.kind = nkRefTy
|
||||
a.info = n.info
|
||||
let u = getNullValue(t.sons[0], n.info)
|
||||
a.kind = u.kind
|
||||
a.typ = t
|
||||
a.sons = nil
|
||||
addSon(a, getNullValue(t.sons[0], n.info))
|
||||
shallowCopy(a.sons, u.sons)
|
||||
result = emptyNode
|
||||
when false:
|
||||
a.kind = nkRefTy
|
||||
a.info = n.info
|
||||
a.typ = t
|
||||
a.sons = nil
|
||||
addSon(a, getNullValue(t.sons[0], n.info))
|
||||
result = emptyNode
|
||||
|
||||
proc evalDeref(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = evalAux(c, n.sons[0], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], {efLValue})
|
||||
case result.kind
|
||||
of nkNilLit: stackTrace(c, n, errNilAccess)
|
||||
of nkNilLit: stackTrace(c, n.info, errNilAccess)
|
||||
of nkRefTy:
|
||||
# XXX efLValue?
|
||||
result = result.sons[0]
|
||||
else:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
if skipTypes(n.sons[0].typ, abstractInst).kind != tyRef:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
proc evalAddr(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = evalAux(c, n.sons[0], {efLValue})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], {efLValue})
|
||||
var a = result
|
||||
var t = newType(tyPtr, c.module)
|
||||
addSonSkipIntLit(t, a.typ)
|
||||
@@ -680,24 +681,22 @@ proc evalUpConv(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
var dest = skipTypes(n.typ, abstractPtrs)
|
||||
var src = skipTypes(result.typ, abstractPtrs)
|
||||
if inheritanceDiff(src, dest) > 0:
|
||||
stackTrace(c, n, errInvalidConversionFromTypeX, typeToString(src))
|
||||
stackTrace(c, n.info, errInvalidConversionFromTypeX, typeToString(src))
|
||||
|
||||
proc evalRangeChck(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[0], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[0], {})
|
||||
var x = result
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[1], {})
|
||||
var a = result
|
||||
result = evalAux(c, n.sons[2], {})
|
||||
if isSpecial(result): return
|
||||
evalX(n.sons[2], {})
|
||||
var b = result
|
||||
if leValueConv(a, x) and leValueConv(x, b):
|
||||
result = x # a <= x and x <= b
|
||||
result.typ = n.typ
|
||||
else:
|
||||
stackTrace(c, n, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
|
||||
typeToString(n.sons[0].typ), typeToString(n.typ)])
|
||||
stackTrace(c, n.info, errGenerated,
|
||||
msgKindToString(errIllegalConvFromXtoY) % [
|
||||
typeToString(n.sons[0].typ), typeToString(n.typ)])
|
||||
|
||||
proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalAux(c, n.sons[0], {})
|
||||
@@ -721,7 +720,7 @@ proc evalRaise(c: PEvalContext, n: PNode): PNode =
|
||||
elif c.lastException != nil:
|
||||
result = c.lastException
|
||||
else:
|
||||
stackTrace(c, n, errExceptionAlreadyHandled)
|
||||
stackTrace(c, n.info, errExceptionAlreadyHandled)
|
||||
result = newNodeIT(nkExceptBranch, n.info, nil)
|
||||
addSon(result, ast.emptyNode)
|
||||
else:
|
||||
@@ -739,10 +738,12 @@ proc evalProc(c: PEvalContext, n: PNode): PNode =
|
||||
if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty):
|
||||
var v = n.sons[resultPos].sym
|
||||
result = getNullValue(v.typ, n.info)
|
||||
IdNodeTablePut(c.tos.mapping, v, result)
|
||||
if c.tos.slots.len == 0: setLen(c.tos.slots, 1)
|
||||
c.tos.slots[0] = result
|
||||
#IdNodeTablePut(c.tos.mapping, v, result)
|
||||
result = evalAux(c, s.getBody, {})
|
||||
if result.kind == nkReturnToken:
|
||||
result = IdNodeTableGet(c.tos.mapping, v)
|
||||
if result.kind == nkReturnToken:
|
||||
result = c.tos.slots[0]
|
||||
else:
|
||||
result = evalAux(c, s.getBody, {})
|
||||
if result.kind == nkReturnToken:
|
||||
@@ -891,17 +892,10 @@ proc evalRepr(c: PEvalContext, n: PNode): PNode =
|
||||
proc isEmpty(n: PNode): bool =
|
||||
result = n != nil and n.kind == nkEmpty
|
||||
|
||||
# The lexer marks multi-line strings as residing at the line where they
|
||||
# are closed. This function returns the line where the string begins
|
||||
# Maybe the lexer should mark both the beginning and the end of expressions,
|
||||
# then this function could be removed.
|
||||
proc stringStartingLine(s: PNode): int =
|
||||
result = s.info.line.int - countLines(s.strVal)
|
||||
|
||||
proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
|
||||
var code = evalAux(c, n.sons[1], {})
|
||||
var ast = parseString(code.getStrValue, code.info.toFilename,
|
||||
code.stringStartingLine)
|
||||
code.info.line.int)
|
||||
if sonsLen(ast) != 1:
|
||||
GlobalError(code.info, errExprExpected, "multiple statements")
|
||||
result = ast.sons[0]
|
||||
@@ -910,51 +904,23 @@ proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
|
||||
proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
|
||||
var code = evalAux(c, n.sons[1], {})
|
||||
result = parseString(code.getStrValue, code.info.toFilename,
|
||||
code.stringStartingLine)
|
||||
code.info.line.int)
|
||||
#result.typ = newType(tyStmt, c.module)
|
||||
|
||||
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||
## XXX: This should be pretty much guaranteed to be true
|
||||
# by the type traits procs' signatures, but until the
|
||||
# code is more mature it doesn't hurt to be extra safe
|
||||
internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
|
||||
|
||||
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
|
||||
case n.sons[0].sym.name.s.normalize
|
||||
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
|
||||
let typ = operand.typ.skipTypes({tyTypeDesc})
|
||||
case trait.sym.name.s.normalize
|
||||
of "name":
|
||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||
result.typ = newType(tyString, context)
|
||||
result.info = n.info
|
||||
result.info = trait.info
|
||||
of "arity":
|
||||
result = newIntNode(nkIntLit, typ.n.len-1)
|
||||
result.typ = newType(tyInt, context)
|
||||
result.info = trait.info
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
proc evalIsOp*(n: PNode): PNode =
|
||||
InternalAssert n.sonsLen == 3 and
|
||||
n[1].kind == nkSym and n[1].sym.kind == skType and
|
||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||
|
||||
let t1 = n[1].sym.typ
|
||||
|
||||
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
||||
case n[2].strVal.normalize
|
||||
of "closure":
|
||||
let t = skipTypes(t1, abstractRange)
|
||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||
t.callConv == ccClosure and
|
||||
tfIterator notin t.flags))
|
||||
of "iterator":
|
||||
let t = skipTypes(t1, abstractRange)
|
||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||
t.callConv == ccClosure and
|
||||
tfIterator in t.flags))
|
||||
else:
|
||||
let t2 = n[2].typ
|
||||
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
|
||||
else: sameType(t1, t2)
|
||||
result = newIntNode(nkIntLit, ord(match))
|
||||
|
||||
result.typ = n.typ
|
||||
|
||||
proc expectString(n: PNode) =
|
||||
if n.kind notin nkStrKinds:
|
||||
GlobalError(n.info, errStringLiteralExpected)
|
||||
@@ -1046,11 +1012,11 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
of mParseStmtToAst: result = evalParseStmt(c, n)
|
||||
of mExpandToAst: result = evalExpandToAst(c, n)
|
||||
of mTypeTrait:
|
||||
n.sons[1] = evalAux(c, n.sons[1], {})
|
||||
result = evalTypeTrait(n, c.module)
|
||||
let operand = evalAux(c, n.sons[1], {})
|
||||
result = evalTypeTrait(n[0], operand, c.module)
|
||||
of mIs:
|
||||
n.sons[1] = evalAux(c, n.sons[1], {})
|
||||
result = evalIsOp(n)
|
||||
result = c.handleIsOperator(n)
|
||||
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
||||
of mStaticExec:
|
||||
let cmd = evalAux(c, n.sons[1], {})
|
||||
@@ -1064,7 +1030,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
case a.kind
|
||||
of nkEmpty..nkNilLit: nil
|
||||
else: result.intVal = sonsLen(a)
|
||||
of mNChild:
|
||||
of mNChild:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
var a = result
|
||||
@@ -1075,7 +1041,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result = a.sons[int(k)]
|
||||
if result == nil: result = newNode(nkEmpty)
|
||||
else:
|
||||
stackTrace(c, n, errIndexOutOfBounds)
|
||||
stackTrace(c, n.info, errIndexOutOfBounds)
|
||||
result = emptyNode
|
||||
of mNSetChild:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
@@ -1090,7 +1056,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
if (k >= 0) and (k < sonsLen(a)) and not (a.kind in {nkEmpty..nkNilLit}):
|
||||
a.sons[int(k)] = result
|
||||
else:
|
||||
stackTrace(c, n, errIndexOutOfBounds)
|
||||
stackTrace(c, n.info, errIndexOutOfBounds)
|
||||
result = emptyNode
|
||||
of mNAdd:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
@@ -1133,7 +1099,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result = newNodeIT(nkIntLit, n.info, n.typ)
|
||||
case a.kind
|
||||
of nkCharLit..nkInt64Lit: result.intVal = a.intVal
|
||||
else: stackTrace(c, n, errFieldXNotFound, "intVal")
|
||||
else: stackTrace(c, n.info, errFieldXNotFound, "intVal")
|
||||
of mNFloatVal:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
@@ -1141,15 +1107,15 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result = newNodeIT(nkFloatLit, n.info, n.typ)
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat64Lit: result.floatVal = a.floatVal
|
||||
else: stackTrace(c, n, errFieldXNotFound, "floatVal")
|
||||
else: stackTrace(c, n.info, errFieldXNotFound, "floatVal")
|
||||
of mNSymbol:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
if result.kind != nkSym: stackTrace(c, n, errFieldXNotFound, "symbol")
|
||||
if result.kind != nkSym: stackTrace(c, n.info, errFieldXNotFound, "symbol")
|
||||
of mNIdent:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
|
||||
if result.kind != nkIdent: stackTrace(c, n.info, errFieldXNotFound, "ident")
|
||||
of mNGetType:
|
||||
var ast = evalAux(c, n.sons[1], {})
|
||||
InternalAssert c.getType != nil
|
||||
@@ -1161,7 +1127,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result = newNodeIT(nkStrLit, n.info, n.typ)
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = a.strVal
|
||||
else: stackTrace(c, n, errFieldXNotFound, "strVal")
|
||||
else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
|
||||
of mNSetIntVal:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
@@ -1172,7 +1138,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result.kind in {nkCharLit..nkInt64Lit}:
|
||||
a.intVal = result.intVal
|
||||
else:
|
||||
stackTrace(c, n, errFieldXNotFound, "intVal")
|
||||
stackTrace(c, n.info, errFieldXNotFound, "intVal")
|
||||
result = emptyNode
|
||||
of mNSetFloatVal:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
@@ -1184,7 +1150,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result.kind in {nkFloatLit..nkFloat64Lit}:
|
||||
a.floatVal = result.floatVal
|
||||
else:
|
||||
stackTrace(c, n, errFieldXNotFound, "floatVal")
|
||||
stackTrace(c, n.info, errFieldXNotFound, "floatVal")
|
||||
result = emptyNode
|
||||
of mNSetSymbol:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
@@ -1195,7 +1161,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
if a.kind == nkSym and result.kind == nkSym:
|
||||
a.sym = result.sym
|
||||
else:
|
||||
stackTrace(c, n, errFieldXNotFound, "symbol")
|
||||
stackTrace(c, n.info, errFieldXNotFound, "symbol")
|
||||
result = emptyNode
|
||||
of mNSetIdent:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
@@ -1206,7 +1172,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
if a.kind == nkIdent and result.kind == nkIdent:
|
||||
a.ident = result.ident
|
||||
else:
|
||||
stackTrace(c, n, errFieldXNotFound, "ident")
|
||||
stackTrace(c, n.info, errFieldXNotFound, "ident")
|
||||
result = emptyNode
|
||||
of mNSetType:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
@@ -1227,7 +1193,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
if a.kind in {nkStrLit..nkTripleStrLit} and
|
||||
result.kind in {nkStrLit..nkTripleStrLit}:
|
||||
a.strVal = result.strVal
|
||||
else: stackTrace(c, n, errFieldXNotFound, "strVal")
|
||||
else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
|
||||
result = emptyNode
|
||||
of mNNewNimNode:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
@@ -1251,11 +1217,21 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
of mNBindSym:
|
||||
# trivial implementation:
|
||||
result = n.sons[1]
|
||||
of mNGenSym:
|
||||
evalX(n.sons[1], {efLValue})
|
||||
let k = getOrdValue(result)
|
||||
evalX(n.sons[2], {efLValue})
|
||||
let b = result
|
||||
let name = if b.strVal.len == 0: ":tmp" else: b.strVal
|
||||
if k < 0 or k > ord(high(TSymKind)):
|
||||
internalError(n.info, "request to create a symbol with invalid kind")
|
||||
result = newSymNode(newSym(k.TSymKind, name.getIdent, c.module, n.info))
|
||||
incl(result.sym.flags, sfGenSym)
|
||||
of mStrToIdent:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
if not (result.kind in {nkStrLit..nkTripleStrLit}):
|
||||
stackTrace(c, n, errFieldXNotFound, "strVal")
|
||||
stackTrace(c, n.info, errFieldXNotFound, "strVal")
|
||||
return
|
||||
var a = result
|
||||
result = newNodeIT(nkIdent, n.info, n.typ)
|
||||
@@ -1308,7 +1284,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
of mNError:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
stackTrace(c, n, errUser, getStrValue(result))
|
||||
stackTrace(c, n.info, errUser, getStrValue(result))
|
||||
result = emptyNode
|
||||
of mConStrStr:
|
||||
result = evalConStrStr(c, n)
|
||||
@@ -1328,7 +1304,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result.strVal = newString(0)
|
||||
of mNCallSite:
|
||||
if c.callsite != nil: result = c.callsite
|
||||
else: stackTrace(c, n, errFieldXNotFound, "callsite")
|
||||
else: stackTrace(c, n.info, errFieldXNotFound, "callsite")
|
||||
else:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
@@ -1346,13 +1322,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
|
||||
else: result = evalOp(m, n, a, b, cc)
|
||||
|
||||
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = emptyNode
|
||||
dec(gNestedEvals)
|
||||
if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations)
|
||||
if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations)
|
||||
case n.kind
|
||||
of nkSym: result = evalSym(c, n, flags)
|
||||
of nkType..nkNilLit:
|
||||
of nkType..nkNilLit, nkTypeOfExpr:
|
||||
# nkStrLit is VERY common in the traces, so we should avoid
|
||||
# the 'copyNode' here.
|
||||
result = n #.copyNode
|
||||
@@ -1420,7 +1396,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange: result = evalRangeChck(c, n)
|
||||
of nkStringToCString: result = evalConvStrToCStr(c, n)
|
||||
of nkCStringToString: result = evalConvCStrToStr(c, n)
|
||||
of nkStmtListExpr, nkStmtList, nkModule:
|
||||
of nkStmtListExpr, nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = evalAux(c, n.sons[i], flags)
|
||||
case result.kind
|
||||
@@ -1464,28 +1440,22 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
|
||||
result = tryEval(c, n)
|
||||
if result.kind == nkExceptBranch:
|
||||
if sonsLen(result) >= 1:
|
||||
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ))
|
||||
stackTrace(c, n.info, errUnhandledExceptionX, typeToString(result.typ))
|
||||
else:
|
||||
stackTrace(c, result, errCannotInterpretNodeX, renderTree(n))
|
||||
stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
|
||||
|
||||
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
|
||||
var p = newEvalContext(module, mode)
|
||||
proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode =
|
||||
var s = newStackFrame()
|
||||
s.call = e
|
||||
s.prc = prc
|
||||
pushStackFrame(p, s)
|
||||
result = tryEval(p, e)
|
||||
if result != nil and result.kind == nkExceptBranch: result = nil
|
||||
popStackFrame(p)
|
||||
|
||||
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
||||
result = evalConstExprAux(module, e, emConst)
|
||||
|
||||
proc evalStaticExpr*(module: PSym, e: PNode): PNode =
|
||||
result = evalConstExprAux(module, e, emStatic)
|
||||
|
||||
proc setupMacroParam(x: PNode): PNode =
|
||||
result = x
|
||||
if result.kind == nkHiddenStdConv: result = result.sons[1]
|
||||
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
|
||||
|
||||
proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
||||
# XXX GlobalError() is ugly here, but I don't know a better solution for now
|
||||
@@ -1496,16 +1466,17 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
||||
c.callsite = nOrig
|
||||
var s = newStackFrame()
|
||||
s.call = n
|
||||
s.prc = sym
|
||||
var L = n.safeLen
|
||||
if L == 0: L = 1
|
||||
setlen(s.params, L)
|
||||
setlen(s.slots, L)
|
||||
# return value:
|
||||
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
|
||||
s.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
|
||||
# setup parameters:
|
||||
for i in 1 .. < L: s.params[i] = setupMacroParam(n.sons[i])
|
||||
for i in 1 .. < L: s.slots[i] = setupMacroParam(n.sons[i])
|
||||
pushStackFrame(c, s)
|
||||
discard eval(c, sym.getBody)
|
||||
result = s.params[0]
|
||||
discard eval(c, optBody(c, sym))
|
||||
result = s.slots[0]
|
||||
popStackFrame(c)
|
||||
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
|
||||
dec(evalTemplateCounter)
|
||||
@@ -1521,10 +1492,11 @@ var oldErrorCount: int
|
||||
|
||||
proc myProcess(c: PPassContext, n: PNode): PNode =
|
||||
# don't eval errornous code:
|
||||
if oldErrorCount != msgs.gErrorCounter:
|
||||
oldErrorCount = msgs.gErrorCounter
|
||||
return n
|
||||
result = eval(PEvalContext(c), n)
|
||||
if oldErrorCount == msgs.gErrorCounter:
|
||||
result = eval(PEvalContext(c), n)
|
||||
else:
|
||||
result = n
|
||||
oldErrorCount = msgs.gErrorCounter
|
||||
|
||||
const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -16,9 +16,14 @@ import
|
||||
type
|
||||
TemplCtx {.pure, final.} = object
|
||||
owner, genSymOwner: PSym
|
||||
instLines: bool # use the instantiation lines numbers
|
||||
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
|
||||
# new symbol
|
||||
|
||||
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
||||
result = copyNode(a)
|
||||
if ctx.instLines: result.info = b.info
|
||||
|
||||
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
case templ.kind
|
||||
of nkSym:
|
||||
@@ -31,49 +36,23 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
else:
|
||||
result.add copyTree(x)
|
||||
else:
|
||||
InternalAssert sfGenSym in s.flags
|
||||
var x = PSym(IdTableGet(c.mapping, s))
|
||||
internalAssert sfGenSym in s.flags
|
||||
var x = PSym(idTableGet(c.mapping, s))
|
||||
if x == nil:
|
||||
x = copySym(s, false)
|
||||
x.owner = c.genSymOwner
|
||||
IdTablePut(c.mapping, s, x)
|
||||
result.add newSymNode(x, templ.info)
|
||||
idTablePut(c.mapping, s, x)
|
||||
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
|
||||
else:
|
||||
result.add copyNode(templ)
|
||||
result.add copyNode(c, templ, actual)
|
||||
of nkNone..nkIdent, nkType..nkNilLit: # atom
|
||||
result.add copyNode(templ)
|
||||
result.add copyNode(c, templ, actual)
|
||||
else:
|
||||
var res = copyNode(templ)
|
||||
var res = copyNode(c, templ, actual)
|
||||
for i in countup(0, sonsLen(templ) - 1):
|
||||
evalTemplateAux(templ.sons[i], actual, c, res)
|
||||
result.add res
|
||||
|
||||
when false:
|
||||
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx): PNode =
|
||||
case templ.kind
|
||||
of nkSym:
|
||||
var s = templ.sym
|
||||
if s.owner.id == c.owner.id:
|
||||
if s.kind == skParam:
|
||||
result = copyTree(actual.sons[s.position])
|
||||
else:
|
||||
InternalAssert sfGenSym in s.flags
|
||||
var x = PSym(IdTableGet(c.mapping, s))
|
||||
if x == nil:
|
||||
x = copySym(s, false)
|
||||
x.owner = c.genSymOwner
|
||||
IdTablePut(c.mapping, s, x)
|
||||
result = newSymNode(x, templ.info)
|
||||
else:
|
||||
result = copyNode(templ)
|
||||
of nkNone..nkIdent, nkType..nkNilLit: # atom
|
||||
result = copyNode(templ)
|
||||
else:
|
||||
result = copyNode(templ)
|
||||
newSons(result, sonsLen(templ))
|
||||
for i in countup(0, sonsLen(templ) - 1):
|
||||
result.sons[i] = evalTemplateAux(templ.sons[i], actual, c)
|
||||
|
||||
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
# if the template has zero arguments, it can be called without ``()``
|
||||
# `n` is then a nkSym or something similar
|
||||
@@ -83,13 +62,13 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
a = sonsLen(n)
|
||||
else: a = 0
|
||||
var f = s.typ.sonsLen
|
||||
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
|
||||
if a > f: globalError(n.info, errWrongNumberOfArguments)
|
||||
|
||||
result = newNodeI(nkArgList, n.info)
|
||||
for i in countup(1, f - 1):
|
||||
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
||||
if arg == nil or arg.kind == nkEmpty:
|
||||
LocalError(n.info, errWrongNumberOfArguments)
|
||||
localError(n.info, errWrongNumberOfArguments)
|
||||
addSon(result, arg)
|
||||
|
||||
var evalTemplateCounter* = 0
|
||||
@@ -98,7 +77,7 @@ var evalTemplateCounter* = 0
|
||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
|
||||
inc(evalTemplateCounter)
|
||||
if evalTemplateCounter > 100:
|
||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||
globalError(n.info, errTemplateInstantiationTooNested)
|
||||
result = n
|
||||
|
||||
# replace each param by the corresponding node:
|
||||
@@ -114,11 +93,13 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
|
||||
evalTemplateAux(body, args, ctx, result)
|
||||
if result.len == 1: result = result.sons[0]
|
||||
else:
|
||||
GlobalError(result.info, errIllFormedAstX,
|
||||
globalError(result.info, errIllFormedAstX,
|
||||
renderTree(result, {renderNoComments}))
|
||||
else:
|
||||
result = copyNode(body)
|
||||
#evalTemplateAux(body, args, ctx, result)
|
||||
ctx.instLines = body.kind notin {nkStmtList, nkStmtListExpr,
|
||||
nkBlockStmt, nkBlockExpr}
|
||||
if ctx.instLines: result.info = n.info
|
||||
for i in countup(0, safeLen(body) - 1):
|
||||
evalTemplateAux(body.sons[i], args, ctx, result)
|
||||
|
||||
|
||||
@@ -16,13 +16,16 @@ import
|
||||
type
|
||||
TSystemCC* = enum
|
||||
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
|
||||
ccTcc, ccPcc, ccUcc, ccIcl, ccGpp
|
||||
ccTcc, ccPcc, ccUcc, ccIcl
|
||||
TInfoCCProp* = enum # properties of the C compiler:
|
||||
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
|
||||
hasComputedGoto, # CC has computed goto (GNU C extension)
|
||||
hasCpp, # CC is/contains a C++ compiler
|
||||
hasAssume, # CC has __assume (Visual C extension)
|
||||
hasGcGuard # CC supports GC_GUARD to keep stack roots
|
||||
hasGcGuard, # CC supports GC_GUARD to keep stack roots
|
||||
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
|
||||
hasNakedDeclspec, # CC has __declspec(naked)
|
||||
hasNakedAttribute # CC has __attribute__((naked))
|
||||
TInfoCCProps* = set[TInfoCCProp]
|
||||
TInfoCC* = tuple[
|
||||
name: string, # the short name of the compiler
|
||||
@@ -30,11 +33,12 @@ type
|
||||
optSpeed: string, # the options for optimization for speed
|
||||
optSize: string, # the options for optimization for size
|
||||
compilerExe: string, # the compiler's executable
|
||||
cppCompiler: string, # name of the C++ compiler's executable (if supported)
|
||||
compileTmpl: string, # the compile command template
|
||||
buildGui: string, # command to build a GUI application
|
||||
buildDll: string, # command to build a shared library
|
||||
buildLib: string, # command to build a static library
|
||||
linkerExe: string, # the linker's executable
|
||||
linkerExe: string, # the linker's executable (if not matching compiler's)
|
||||
linkTmpl: string, # command to link files to produce an exe
|
||||
includeCmd: string, # command to add an include dir
|
||||
linkDirCmd: string, # command to add a lib dir
|
||||
@@ -43,6 +47,8 @@ type
|
||||
pic: string, # command for position independent code
|
||||
# used on some platforms
|
||||
asmStmtFrmt: string, # format of ASM statement
|
||||
structStmtFmt: string, # Format for struct statement
|
||||
packedPragma: string, # Attribute/pragma to make struct packed (1-byte aligned)
|
||||
props: TInfoCCProps] # properties of the C compiler
|
||||
|
||||
|
||||
@@ -60,11 +66,12 @@ compiler gcc:
|
||||
optSpeed: " -O3 -ffast-math ",
|
||||
optSize: " -Os -ffast-math ",
|
||||
compilerExe: "gcc",
|
||||
cppCompiler: "g++",
|
||||
compileTmpl: "-c $options $include -o $objfile $file",
|
||||
buildGui: " -mwindows",
|
||||
buildDll: " -shared",
|
||||
buildLib: "ar rcs $libfile $objfiles",
|
||||
linkerExe: "gcc",
|
||||
linkerExe: "",
|
||||
linkTmpl: "$buildgui $builddll -o $exefile $objfiles $options",
|
||||
includeCmd: " -I",
|
||||
linkDirCmd: " -L",
|
||||
@@ -72,33 +79,25 @@ compiler gcc:
|
||||
debug: "",
|
||||
pic: "-fPIC",
|
||||
asmStmtFrmt: "asm($1);$n",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard})
|
||||
|
||||
compiler gpp:
|
||||
result = gcc()
|
||||
|
||||
result.name = "gpp"
|
||||
result.compilerExe = "g++"
|
||||
result.linkerExe = "g++"
|
||||
|
||||
result.buildDll = " -mdll"
|
||||
# XXX: Hmm, I'm keeping this from the previos version,
|
||||
# but my gcc doesn't even have such an option (is this mingw?)
|
||||
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
|
||||
packedPragma: "__attribute__((__packed__))",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasNakedAttribute})
|
||||
|
||||
compiler llvmGcc:
|
||||
result = gcc()
|
||||
|
||||
result.name = "llvm_gcc"
|
||||
result.compilerExe = "llvm-gcc"
|
||||
result.cppCompiler = "llvm-g++"
|
||||
result.buildLib = "llvm-ar rcs $libfile $objfiles"
|
||||
result.linkerExe = "llvm-gcc"
|
||||
|
||||
compiler clang:
|
||||
result = llvmGcc()
|
||||
|
||||
result.name = "clang"
|
||||
result.compilerExe = "clang"
|
||||
result.linkerExe = "clang"
|
||||
result.cppCompiler = "clang++"
|
||||
|
||||
compiler vcc:
|
||||
result = (
|
||||
@@ -107,6 +106,7 @@ compiler vcc:
|
||||
optSpeed: " /Ogityb2 /G7 /arch:SSE2 ",
|
||||
optSize: " /O1 /G7 ",
|
||||
compilerExe: "cl",
|
||||
cppCompiler: "cl",
|
||||
compileTmpl: "/c $options $include /Fo$objfile $file",
|
||||
buildGui: " /link /SUBSYSTEM:WINDOWS ",
|
||||
buildDll: " /LD",
|
||||
@@ -119,7 +119,9 @@ compiler vcc:
|
||||
debug: " /GZ /Zi ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
props: {hasCpp, hasAssume})
|
||||
structStmtFmt: "$3$n$1 $2",
|
||||
packedPragma: "#pragma pack(1)",
|
||||
props: {hasCpp, hasAssume, hasNakedDeclspec})
|
||||
|
||||
compiler icl:
|
||||
# Intel compilers try to imitate the native ones (gcc and msvc)
|
||||
@@ -127,7 +129,7 @@ compiler icl:
|
||||
result = vcc()
|
||||
else:
|
||||
result = gcc()
|
||||
|
||||
|
||||
result.name = "icl"
|
||||
result.compilerExe = "icl"
|
||||
result.linkerExe = "icl"
|
||||
@@ -139,6 +141,7 @@ compiler lcc:
|
||||
optSpeed: " -O -p6 ",
|
||||
optSize: " -O -p6 ",
|
||||
compilerExe: "lcc",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "$options $include -Fo$objfile $file",
|
||||
buildGui: " -subsystem windows",
|
||||
buildDll: " -dll",
|
||||
@@ -151,6 +154,8 @@ compiler lcc:
|
||||
debug: " -g5 ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "_asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
packedPragma: "", # XXX: not supported yet
|
||||
props: {})
|
||||
|
||||
compiler bcc:
|
||||
@@ -160,6 +165,7 @@ compiler bcc:
|
||||
optSpeed: " -O2 -6 ",
|
||||
optSize: " -O1 -6 ",
|
||||
compilerExe: "bcc32",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -o$objfile $file",
|
||||
buildGui: " -tW",
|
||||
buildDll: " -tWD",
|
||||
@@ -172,6 +178,8 @@ compiler bcc:
|
||||
debug: "",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
packedPragma: "", # XXX: not supported yet
|
||||
props: {hasCpp})
|
||||
|
||||
compiler dmc:
|
||||
@@ -181,6 +189,7 @@ compiler dmc:
|
||||
optSpeed: " -ff -o -6 ",
|
||||
optSize: " -ff -o -6 ",
|
||||
compilerExe: "dmc",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -o$objfile $file",
|
||||
buildGui: " -L/exet:nt/su:windows",
|
||||
buildDll: " -WD",
|
||||
@@ -193,6 +202,8 @@ compiler dmc:
|
||||
debug: " -g ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$3$n$1 $2",
|
||||
packedPragma: "#pragma pack(1)",
|
||||
props: {hasCpp})
|
||||
|
||||
compiler wcc:
|
||||
@@ -202,6 +213,7 @@ compiler wcc:
|
||||
optSpeed: " -ox -on -6 -d0 -fp6 -zW ",
|
||||
optSize: "",
|
||||
compilerExe: "wcl386",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -fo=$objfile $file",
|
||||
buildGui: " -bw",
|
||||
buildDll: " -bd",
|
||||
@@ -214,6 +226,8 @@ compiler wcc:
|
||||
debug: " -d2 ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
packedPragma: "", # XXX: not supported yet
|
||||
props: {hasCpp})
|
||||
|
||||
compiler tcc:
|
||||
@@ -223,6 +237,7 @@ compiler tcc:
|
||||
optSpeed: "",
|
||||
optSize: "",
|
||||
compilerExe: "tcc",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -o $objfile $file",
|
||||
buildGui: "UNAVAILABLE!",
|
||||
buildDll: " -shared",
|
||||
@@ -235,6 +250,8 @@ compiler tcc:
|
||||
debug: " -g ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
packedPragma: "", # XXX: not supported yet
|
||||
props: {hasSwitchRange, hasComputedGoto})
|
||||
|
||||
compiler pcc:
|
||||
@@ -245,6 +262,7 @@ compiler pcc:
|
||||
optSpeed: " -Ox ",
|
||||
optSize: " -Os ",
|
||||
compilerExe: "cc",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -Fo$objfile $file",
|
||||
buildGui: " -SUBSYSTEM:WINDOWS",
|
||||
buildDll: " -DLL",
|
||||
@@ -257,6 +275,8 @@ compiler pcc:
|
||||
debug: " -Zi ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
packedPragma: "", # XXX: not supported yet
|
||||
props: {})
|
||||
|
||||
compiler ucc:
|
||||
@@ -266,6 +286,7 @@ compiler ucc:
|
||||
optSpeed: " -O3 ",
|
||||
optSize: " -O1 ",
|
||||
compilerExe: "cc",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -o $objfile $file",
|
||||
buildGui: "",
|
||||
buildDll: " -shared ",
|
||||
@@ -278,6 +299,8 @@ compiler ucc:
|
||||
debug: "",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
packedPragma: "", # XXX: not supported yet
|
||||
props: {})
|
||||
|
||||
const
|
||||
@@ -293,17 +316,16 @@ const
|
||||
tcc(),
|
||||
pcc(),
|
||||
ucc(),
|
||||
icl(),
|
||||
gpp()]
|
||||
icl()]
|
||||
|
||||
const
|
||||
hExt* = "h"
|
||||
hExt* = ".h"
|
||||
|
||||
var
|
||||
cCompiler* = ccGcc # the used compiler
|
||||
|
||||
cExt* = "c" # extension of generated C/C++ files
|
||||
# (can be changed to .cpp later)
|
||||
cExt* = ".c" # extension of generated C/C++ files
|
||||
# (can be changed to .cpp later)
|
||||
|
||||
cIncludes*: seq[string] = @[] # directories to search for included files
|
||||
cLibs*: seq[string] = @[] # directories to search for lib files
|
||||
@@ -320,7 +342,7 @@ var
|
||||
compileOptions: string = ""
|
||||
ccompilerpath: string = ""
|
||||
|
||||
proc NameToCC*(name: string): TSystemCC =
|
||||
proc nameToCC*(name: string): TSystemCC =
|
||||
for i in countup(succ(ccNone), high(TSystemCC)):
|
||||
if cmpIgnoreStyle(name, CC[i].name) == 0:
|
||||
return i
|
||||
@@ -331,8 +353,8 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
|
||||
# for niminst support
|
||||
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
|
||||
optCompileOnly notin gGlobalOptions:
|
||||
let fullCCname = platform.cpu[targetCPU].name & '.' &
|
||||
platform.os[targetOS].name & '.' &
|
||||
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
||||
platform.OS[targetOS].name & '.' &
|
||||
CC[c].name & suffix
|
||||
result = getConfigVar(fullCCname)
|
||||
if result.len == 0:
|
||||
@@ -342,13 +364,13 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
|
||||
result = getConfigVar(CC[c].name & suffix)
|
||||
|
||||
proc setCC*(ccname: string) =
|
||||
ccompiler = nameToCC(ccname)
|
||||
if ccompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
||||
compileOptions = getConfigVar(ccompiler, ".options.always")
|
||||
linkOptions = getConfigVar(ccompiler, ".options.linker")
|
||||
ccompilerpath = getConfigVar(ccompiler, ".path")
|
||||
cCompiler = nameToCC(ccname)
|
||||
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
||||
compileOptions = getConfigVar(cCompiler, ".options.always")
|
||||
linkOptions = getConfigVar(cCompiler, ".options.linker")
|
||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[ccompiler].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
|
||||
proc addOpt(dest: var string, src: string) =
|
||||
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
|
||||
@@ -364,20 +386,20 @@ proc addCompileOption*(option: string) =
|
||||
proc initVars*() =
|
||||
# we need to define the symbol here, because ``CC`` may have never been set!
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[ccompiler].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
if gCmd == cmdCompileToCpp: cExt = ".cpp"
|
||||
elif gCmd == cmdCompileToOC: cExt = ".m"
|
||||
addCompileOption(getConfigVar(ccompiler, ".options.always"))
|
||||
addLinkOption(getConfigVar(ccompiler, ".options.linker"))
|
||||
if len(ccompilerPath) == 0:
|
||||
ccompilerpath = getConfigVar(ccompiler, ".path")
|
||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
||||
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||
if len(ccompilerpath) == 0:
|
||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||
|
||||
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
|
||||
result = completeGeneratedFilePath(cfile, createSubDir)
|
||||
|
||||
proc toObjFile*(filenameWithoutExt: string): string =
|
||||
# Object file for compilation
|
||||
result = changeFileExt(filenameWithoutExt, cc[ccompiler].objExt)
|
||||
result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt)
|
||||
|
||||
proc addFileToCompile*(filename: string) =
|
||||
appendStr(toCompile, filename)
|
||||
@@ -396,28 +418,28 @@ proc addFileToLink*(filename: string) =
|
||||
# BUGFIX: was ``appendStr``
|
||||
|
||||
proc execExternalProgram*(cmd: string) =
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 0: MsgWriteln(cmd)
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd)
|
||||
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
|
||||
|
||||
proc generateScript(projectFile: string, script: PRope) =
|
||||
let (dir, name, ext) = splitFile(projectFile)
|
||||
WriteRope(script, dir / addFileExt("compile_" & name,
|
||||
platform.os[targetOS].scriptExt))
|
||||
writeRope(script, dir / addFileExt("compile_" & name,
|
||||
platform.OS[targetOS].scriptExt))
|
||||
|
||||
proc getOptSpeed(c: TSystemCC): string =
|
||||
result = getConfigVar(c, ".options.speed")
|
||||
if result == "":
|
||||
result = cc[c].optSpeed # use default settings from this file
|
||||
result = CC[c].optSpeed # use default settings from this file
|
||||
|
||||
proc getDebug(c: TSystemCC): string =
|
||||
result = getConfigVar(c, ".options.debug")
|
||||
if result == "":
|
||||
result = cc[c].debug # use default settings from this file
|
||||
result = CC[c].debug # use default settings from this file
|
||||
|
||||
proc getOptSize(c: TSystemCC): string =
|
||||
result = getConfigVar(c, ".options.size")
|
||||
if result == "":
|
||||
result = cc[c].optSize # use default settings from this file
|
||||
result = CC[c].optSize # use default settings from this file
|
||||
|
||||
proc noAbsolutePaths: bool {.inline.} =
|
||||
# We used to check current OS != specified OS, but this makes no sense
|
||||
@@ -432,92 +454,102 @@ const
|
||||
|
||||
var fileCounter: int
|
||||
|
||||
proc add(s: var string, many: openarray[string]) =
|
||||
proc add(s: var string, many: openArray[string]) =
|
||||
s.add many.join
|
||||
|
||||
proc CFileSpecificOptions(cfilename: string): string =
|
||||
proc cFileSpecificOptions(cfilename: string): string =
|
||||
result = compileOptions
|
||||
var trunk = splitFile(cfilename).name
|
||||
if optCDebug in gGlobalOptions:
|
||||
var key = trunk & ".debug"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
else: addOpt(result, getDebug(ccompiler))
|
||||
else: addOpt(result, getDebug(cCompiler))
|
||||
if optOptimizeSpeed in gOptions:
|
||||
var key = trunk & ".speed"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
else: addOpt(result, getOptSpeed(ccompiler))
|
||||
else: addOpt(result, getOptSpeed(cCompiler))
|
||||
elif optOptimizeSize in gOptions:
|
||||
var key = trunk & ".size"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
else: addOpt(result, getOptSize(ccompiler))
|
||||
else: addOpt(result, getOptSize(cCompiler))
|
||||
var key = trunk & ".always"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
|
||||
proc getCompileOptions: string =
|
||||
result = CFileSpecificOptions("__dummy__")
|
||||
result = cFileSpecificOptions("__dummy__")
|
||||
|
||||
proc getLinkOptions: string =
|
||||
result = linkOptions
|
||||
for linkedLib in items(cLinkedLibs):
|
||||
result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteIfContainsWhite)
|
||||
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
|
||||
for libDir in items(cLibs):
|
||||
result.add([cc[ccompiler].linkDirCmd, libDir.quoteIfContainsWhite])
|
||||
result.add([CC[cCompiler].linkDirCmd, libDir.quoteShell])
|
||||
|
||||
proc needsExeExt(): bool {.inline.} =
|
||||
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
||||
(platform.hostOS == osWindows)
|
||||
|
||||
proc getCompilerExe(compiler: TSystemCC): string =
|
||||
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
|
||||
else: CC[compiler].compilerExe
|
||||
if result.len == 0:
|
||||
rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
|
||||
|
||||
proc getLinkerExe(compiler: TSystemCC): string =
|
||||
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||
else: compiler.getCompilerExe
|
||||
|
||||
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||
var c = ccompiler
|
||||
var options = CFileSpecificOptions(cfilename)
|
||||
var c = cCompiler
|
||||
var options = cFileSpecificOptions(cfilename)
|
||||
var exe = getConfigVar(c, ".exe")
|
||||
if exe.len == 0: exe = cc[c].compilerExe
|
||||
if exe.len == 0: exe = c.getCompilerExe
|
||||
|
||||
if needsExeExt(): exe = addFileExt(exe, "exe")
|
||||
if optGenDynLib in gGlobalOptions and
|
||||
ospNeedsPIC in platform.OS[targetOS].props:
|
||||
add(options, ' ' & cc[c].pic)
|
||||
add(options, ' ' & CC[c].pic)
|
||||
|
||||
var includeCmd, compilePattern: string
|
||||
if not noAbsolutePaths():
|
||||
# compute include paths:
|
||||
includeCmd = cc[c].includeCmd & quoteIfContainsWhite(libpath)
|
||||
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
||||
|
||||
for includeDir in items(cIncludes):
|
||||
includeCmd.add([cc[c].includeCmd, includeDir.quoteIfContainsWhite])
|
||||
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
|
||||
|
||||
compilePattern = JoinPath(ccompilerpath, exe)
|
||||
compilePattern = joinPath(ccompilerpath, exe)
|
||||
else:
|
||||
includeCmd = ""
|
||||
compilePattern = cc[c].compilerExe
|
||||
compilePattern = c.getCompilerExe
|
||||
|
||||
var cfile = if noAbsolutePaths(): extractFileName(cfilename)
|
||||
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
|
||||
else: cfilename
|
||||
var objfile = if not isExternal or noAbsolutePaths():
|
||||
toObjFile(cfile)
|
||||
else:
|
||||
completeCFilePath(toObjFile(cfile))
|
||||
cfile = quoteIfContainsWhite(AddFileExt(cfile, cExt))
|
||||
objfile = quoteIfContainsWhite(objfile)
|
||||
result = quoteIfContainsWhite(compilePattern % [
|
||||
cfile = quoteShell(addFileExt(cfile, cExt))
|
||||
objfile = quoteShell(objfile)
|
||||
result = quoteShell(compilePattern % [
|
||||
"file", cfile, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
|
||||
add(result, ' ')
|
||||
addf(result, cc[c].compileTmpl, [
|
||||
addf(result, CC[c].compileTmpl, [
|
||||
"file", cfile, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nimrod", quoteIfContainsWhite(getPrefixDir()),
|
||||
"lib", quoteIfContainsWhite(libpath)])
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
|
||||
proc footprint(filename: string): TCrc32 =
|
||||
result = crcFromFile(filename) ><
|
||||
platform.OS[targetOS].name ><
|
||||
platform.CPU[targetCPU].name ><
|
||||
extccomp.CC[extccomp.ccompiler].name ><
|
||||
extccomp.CC[extccomp.cCompiler].name ><
|
||||
getCompileCFileCmd(filename, true)
|
||||
|
||||
proc externalFileChanged(filename: string): bool =
|
||||
var crcFile = toGeneratedFile(filename, "crc")
|
||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||
var currentCrc = int(footprint(filename))
|
||||
var f: TFile
|
||||
if open(f, crcFile, fmRead):
|
||||
@@ -537,7 +569,7 @@ proc addExternalFileToCompile*(filename: string) =
|
||||
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
|
||||
appendStr(externalToCompile, filename)
|
||||
|
||||
proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
isExternal: bool) =
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
@@ -550,18 +582,18 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
app(script, tnl)
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc CallCCompiler*(projectfile: string) =
|
||||
proc callCCompiler*(projectfile: string) =
|
||||
var
|
||||
linkCmd, buildgui, builddll: string
|
||||
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||
return # speed up that call if only compiling and no script shall be
|
||||
# generated
|
||||
fileCounter = 0
|
||||
var c = ccompiler
|
||||
var c = cCompiler
|
||||
var script: PRope = nil
|
||||
var cmds: TStringSeq = @[]
|
||||
CompileCFile(toCompile, script, cmds, false)
|
||||
CompileCFile(externalToCompile, script, cmds, true)
|
||||
compileCFile(toCompile, script, cmds, false)
|
||||
compileCFile(externalToCompile, script, cmds, true)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||
var res = 0
|
||||
@@ -579,63 +611,64 @@ proc CallCCompiler*(projectfile: string) =
|
||||
else:
|
||||
rawMessage(errGenerated, " execution of an external program failed; " &
|
||||
"rerun with --parallelBuild:1 to see the error message")
|
||||
if optNoLinking notin gGlobalOptions and cmds.len > 0:
|
||||
if optNoLinking notin gGlobalOptions:
|
||||
# call the linker:
|
||||
var it = PStrEntry(toLink.head)
|
||||
var objfiles = ""
|
||||
while it != nil:
|
||||
let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, quoteIfContainsWhite(
|
||||
addFileExt(objFile, cc[ccompiler].objExt)))
|
||||
add(objfiles, quoteShell(
|
||||
addFileExt(objFile, CC[cCompiler].objExt)))
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
if optGenStaticLib in gGlobalOptions:
|
||||
linkcmd = cc[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
|
||||
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
|
||||
"objfiles", objfiles]
|
||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
||||
else:
|
||||
var linkerExe = getConfigVar(c, ".linkerexe")
|
||||
if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
|
||||
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
|
||||
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
|
||||
if noAbsolutePaths(): linkCmd = quoteIfContainsWhite(linkerExe)
|
||||
else: linkCmd = quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe))
|
||||
if optGenGuiApp in gGlobalOptions: buildGui = cc[c].buildGui
|
||||
else: buildGui = ""
|
||||
if noAbsolutePaths(): linkCmd = quoteShell(linkerExe)
|
||||
else: linkCmd = quoteShell(joinPath(ccompilerpath, linkerExe))
|
||||
if optGenGuiApp in gGlobalOptions: buildgui = CC[c].buildGui
|
||||
else: buildgui = ""
|
||||
var exefile: string
|
||||
if options.outFile.len > 0:
|
||||
exefile = options.outFile
|
||||
elif optGenDynLib in gGlobalOptions:
|
||||
exefile = platform.os[targetOS].dllFrmt % splitFile(projectFile).name
|
||||
buildDll = cc[c].buildDll
|
||||
if optGenDynLib in gGlobalOptions:
|
||||
exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
|
||||
builddll = CC[c].buildDll
|
||||
else:
|
||||
exefile = splitFile(projectFile).name & platform.os[targetOS].exeExt
|
||||
buildDll = ""
|
||||
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
|
||||
builddll = ""
|
||||
if options.outFile.len > 0:
|
||||
exefile = options.outFile.expandTilde
|
||||
if not noAbsolutePaths():
|
||||
exefile = joinPath(splitFile(projectFile).dir, exefile)
|
||||
exefile = quoteIfContainsWhite(exefile)
|
||||
if not exefile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||
exefile = quoteShell(exefile)
|
||||
let linkOptions = getLinkOptions()
|
||||
linkCmd = quoteIfContainsWhite(linkCmd % ["builddll", builddll,
|
||||
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
|
||||
linkCmd.add ' '
|
||||
addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll,
|
||||
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions,
|
||||
"objfiles", objfiles, "exefile", exefile,
|
||||
"nimrod", quoteIfContainsWhite(getPrefixDir()),
|
||||
"lib", quoteIfContainsWhite(libpath)])
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
||||
else:
|
||||
linkCmd = ""
|
||||
if optGenScript in gGlobalOptions:
|
||||
app(script, linkCmd)
|
||||
app(script, tnl)
|
||||
generateScript(projectFile, script)
|
||||
generateScript(projectfile, script)
|
||||
|
||||
proc genMappingFiles(list: TLinkedList): PRope =
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
appf(result, "--file:r\"$1\"$N", [toRope(AddFileExt(it.data, cExt))])
|
||||
appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))])
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc writeMapping*(gSymbolMapping: PRope) =
|
||||
@@ -653,5 +686,5 @@ proc writeMapping*(gSymbolMapping: PRope) =
|
||||
app(code, strutils.escape(libpath))
|
||||
|
||||
appf(code, "\n[Symbols]$n$1", [gSymbolMapping])
|
||||
WriteRope(code, joinPath(gProjectPath, "mapping.txt"))
|
||||
writeRope(code, joinPath(gProjectPath, "mapping.txt"))
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ type
|
||||
indent, emitPar: int
|
||||
x: string # the current input line
|
||||
outp: PLLStream # the ouput will be parsed by pnimsyn
|
||||
subsChar, NimDirective: Char
|
||||
subsChar, nimDirective: char
|
||||
emit, conc, toStr: string
|
||||
curly, bracket, par: int
|
||||
pendingExprLine: bool
|
||||
@@ -37,11 +37,11 @@ const
|
||||
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
||||
|
||||
proc newLine(p: var TTmplParser) =
|
||||
LLStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
|
||||
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
|
||||
p.emitPar = 0
|
||||
if p.info.line > int16(1): LLStreamWrite(p.outp, "\n")
|
||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
||||
if p.pendingExprLine:
|
||||
LLStreamWrite(p.outp, repeatChar(2))
|
||||
llStreamWrite(p.outp, repeatChar(2))
|
||||
p.pendingExprLine = false
|
||||
|
||||
proc scanPar(p: var TTmplParser, d: int) =
|
||||
@@ -55,7 +55,7 @@ proc scanPar(p: var TTmplParser, d: int) =
|
||||
of ']': dec(p.bracket)
|
||||
of '{': inc(p.curly)
|
||||
of '}': dec(p.curly)
|
||||
else: nil
|
||||
else: discard
|
||||
inc(i)
|
||||
|
||||
proc withInExpr(p: TTmplParser): bool {.inline.} =
|
||||
@@ -67,9 +67,9 @@ proc parseLine(p: var TTmplParser) =
|
||||
keyw: string
|
||||
j = 0
|
||||
while p.x[j] == ' ': inc(j)
|
||||
if (p.x[0] == p.NimDirective) and (p.x[0 + 1] == '!'):
|
||||
if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'):
|
||||
newLine(p)
|
||||
elif (p.x[j] == p.NimDirective):
|
||||
elif (p.x[j] == p.nimDirective):
|
||||
newLine(p)
|
||||
inc(j)
|
||||
while p.x[j] == ' ': inc(j)
|
||||
@@ -87,26 +87,26 @@ proc parseLine(p: var TTmplParser) =
|
||||
dec(p.indent, 2)
|
||||
else:
|
||||
p.info.col = int16(j)
|
||||
LocalError(p.info, errXNotAllowedHere, "end")
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent))
|
||||
LLStreamWrite(p.outp, "#end")
|
||||
localError(p.info, errXNotAllowedHere, "end")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, "#end")
|
||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||
wConverter, wMacro, wTemplate, wMethod:
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent))
|
||||
LLStreamWrite(p.outp, substr(p.x, d))
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
inc(p.indent, 2)
|
||||
of wElif, wOf, wElse, wExcept, wFinally:
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent - 2))
|
||||
LLStreamWrite(p.outp, substr(p.x, d))
|
||||
llStreamWrite(p.outp, repeatChar(p.indent - 2))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
of wLet, wVar, wConst, wType:
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent))
|
||||
LLStreamWrite(p.outp, substr(p.x, d))
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
if not p.x.contains({':', '='}):
|
||||
# no inline element --> treat as block:
|
||||
inc(p.indent, 2)
|
||||
else:
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent))
|
||||
LLStreamWrite(p.outp, substr(p.x, d))
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
p.state = psDirective
|
||||
else:
|
||||
# data line
|
||||
@@ -118,15 +118,15 @@ proc parseLine(p: var TTmplParser) =
|
||||
case p.state
|
||||
of psTempl:
|
||||
# next line of string literal:
|
||||
LLStreamWrite(p.outp, p.conc)
|
||||
LLStreamWrite(p.outp, "\n")
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent + 2))
|
||||
LLStreamWrite(p.outp, "\"")
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, "\n")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent + 2))
|
||||
llStreamWrite(p.outp, "\"")
|
||||
of psDirective:
|
||||
newLine(p)
|
||||
LLStreamWrite(p.outp, repeatChar(p.indent))
|
||||
LLStreamWrite(p.outp, p.emit)
|
||||
LLStreamWrite(p.outp, "(\"")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, p.emit)
|
||||
llStreamWrite(p.outp, "(\"")
|
||||
inc(p.emitPar)
|
||||
p.state = psTempl
|
||||
while true:
|
||||
@@ -134,17 +134,17 @@ proc parseLine(p: var TTmplParser) =
|
||||
of '\0':
|
||||
break
|
||||
of '\x01'..'\x1F', '\x80'..'\xFF':
|
||||
LLStreamWrite(p.outp, "\\x")
|
||||
LLStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
|
||||
llStreamWrite(p.outp, "\\x")
|
||||
llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
|
||||
inc(j)
|
||||
of '\\':
|
||||
LLStreamWrite(p.outp, "\\\\")
|
||||
llStreamWrite(p.outp, "\\\\")
|
||||
inc(j)
|
||||
of '\'':
|
||||
LLStreamWrite(p.outp, "\\\'")
|
||||
llStreamWrite(p.outp, "\\\'")
|
||||
inc(j)
|
||||
of '\"':
|
||||
LLStreamWrite(p.outp, "\\\"")
|
||||
llStreamWrite(p.outp, "\\\"")
|
||||
inc(j)
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
@@ -153,59 +153,59 @@ proc parseLine(p: var TTmplParser) =
|
||||
case p.x[j]
|
||||
of '{':
|
||||
p.info.col = int16(j)
|
||||
LLStreamWrite(p.outp, '\"')
|
||||
LLStreamWrite(p.outp, p.conc)
|
||||
LLStreamWrite(p.outp, p.toStr)
|
||||
LLStreamWrite(p.outp, '(')
|
||||
llStreamWrite(p.outp, '\"')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, p.toStr)
|
||||
llStreamWrite(p.outp, '(')
|
||||
inc(j)
|
||||
curly = 0
|
||||
while true:
|
||||
case p.x[j]
|
||||
of '\0':
|
||||
LocalError(p.info, errXExpected, "}")
|
||||
localError(p.info, errXExpected, "}")
|
||||
break
|
||||
of '{':
|
||||
inc(j)
|
||||
inc(curly)
|
||||
LLStreamWrite(p.outp, '{')
|
||||
llStreamWrite(p.outp, '{')
|
||||
of '}':
|
||||
inc(j)
|
||||
if curly == 0: break
|
||||
if curly > 0: dec(curly)
|
||||
LLStreamWrite(p.outp, '}')
|
||||
llStreamWrite(p.outp, '}')
|
||||
else:
|
||||
LLStreamWrite(p.outp, p.x[j])
|
||||
llStreamWrite(p.outp, p.x[j])
|
||||
inc(j)
|
||||
LLStreamWrite(p.outp, ')')
|
||||
LLStreamWrite(p.outp, p.conc)
|
||||
LLStreamWrite(p.outp, '\"')
|
||||
llStreamWrite(p.outp, ')')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, '\"')
|
||||
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF':
|
||||
LLStreamWrite(p.outp, '\"')
|
||||
LLStreamWrite(p.outp, p.conc)
|
||||
LLStreamWrite(p.outp, p.toStr)
|
||||
LLStreamWrite(p.outp, '(')
|
||||
llStreamWrite(p.outp, '\"')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, p.toStr)
|
||||
llStreamWrite(p.outp, '(')
|
||||
while p.x[j] in PatternChars:
|
||||
LLStreamWrite(p.outp, p.x[j])
|
||||
llStreamWrite(p.outp, p.x[j])
|
||||
inc(j)
|
||||
LLStreamWrite(p.outp, ')')
|
||||
LLStreamWrite(p.outp, p.conc)
|
||||
LLStreamWrite(p.outp, '\"')
|
||||
llStreamWrite(p.outp, ')')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, '\"')
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
LLStreamWrite(p.outp, p.subsChar)
|
||||
llStreamWrite(p.outp, p.subsChar)
|
||||
inc(j)
|
||||
else:
|
||||
p.info.col = int16(j)
|
||||
LocalError(p.info, errInvalidExpression, "$")
|
||||
localError(p.info, errInvalidExpression, "$")
|
||||
else:
|
||||
LLStreamWrite(p.outp, p.x[j])
|
||||
llStreamWrite(p.outp, p.x[j])
|
||||
inc(j)
|
||||
LLStreamWrite(p.outp, "\\n\"")
|
||||
llStreamWrite(p.outp, "\\n\"")
|
||||
|
||||
proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
var p: TTmplParser
|
||||
p.info = newLineInfo(filename, 0, 0)
|
||||
p.outp = LLStreamOpen("")
|
||||
p.outp = llStreamOpen("")
|
||||
p.inp = stdin
|
||||
p.subsChar = charArg(call, "subschar", 1, '$')
|
||||
p.nimDirective = charArg(call, "metachar", 2, '#')
|
||||
@@ -213,9 +213,9 @@ proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
p.conc = strArg(call, "conc", 4, " & ")
|
||||
p.toStr = strArg(call, "tostring", 5, "$")
|
||||
p.x = newStringOfCap(120)
|
||||
while LLStreamReadLine(p.inp, p.x):
|
||||
while llStreamReadLine(p.inp, p.x):
|
||||
p.info.line = p.info.line + int16(1)
|
||||
parseLine(p)
|
||||
newLine(p)
|
||||
result = p.outp
|
||||
LLStreamClose(p.inp)
|
||||
llStreamClose(p.inp)
|
||||
|
||||
@@ -16,13 +16,13 @@ import
|
||||
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
|
||||
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream
|
||||
# helpers to retrieve arguments:
|
||||
proc charArg*(n: PNode, name: string, pos: int, default: Char): Char
|
||||
proc charArg*(n: PNode, name: string, pos: int, default: char): char
|
||||
proc strArg*(n: PNode, name: string, pos: int, default: string): string
|
||||
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool
|
||||
# implementation
|
||||
|
||||
proc invalidPragma(n: PNode) =
|
||||
LocalError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
|
||||
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc getArg(n: PNode, name: string, pos: int): PNode =
|
||||
result = nil
|
||||
@@ -30,12 +30,12 @@ proc getArg(n: PNode, name: string, pos: int): PNode =
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == nkExprEqExpr:
|
||||
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
|
||||
if IdentEq(n.sons[i].sons[0].ident, name):
|
||||
if identEq(n.sons[i].sons[0].ident, name):
|
||||
return n.sons[i].sons[1]
|
||||
elif i == pos:
|
||||
return n.sons[i]
|
||||
|
||||
proc charArg(n: PNode, name: string, pos: int, default: Char): Char =
|
||||
proc charArg(n: PNode, name: string, pos: int, default: char): char =
|
||||
var x = getArg(n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind == nkCharLit: result = chr(int(x.intVal))
|
||||
@@ -50,30 +50,30 @@ proc strArg(n: PNode, name: string, pos: int, default: string): string =
|
||||
proc boolArg(n: PNode, name: string, pos: int, default: bool): bool =
|
||||
var x = getArg(n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif (x.kind == nkIdent) and IdentEq(x.ident, "true"): result = true
|
||||
elif (x.kind == nkIdent) and IdentEq(x.ident, "false"): result = false
|
||||
elif (x.kind == nkIdent) and identEq(x.ident, "true"): result = true
|
||||
elif (x.kind == nkIdent) and identEq(x.ident, "false"): result = false
|
||||
else: invalidPragma(n)
|
||||
|
||||
proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
var pattern = strArg(call, "startswith", 1, "")
|
||||
var leading = boolArg(call, "leading", 2, true)
|
||||
var trailing = boolArg(call, "trailing", 3, true)
|
||||
result = LLStreamOpen("")
|
||||
result = llStreamOpen("")
|
||||
var line = newStringOfCap(80)
|
||||
while LLStreamReadLine(stdin, line):
|
||||
while llStreamReadLine(stdin, line):
|
||||
var stripped = strip(line, leading, trailing)
|
||||
if (len(pattern) == 0) or startsWith(stripped, pattern):
|
||||
LLStreamWriteln(result, stripped)
|
||||
llStreamWriteln(result, stripped)
|
||||
else:
|
||||
LLStreamWriteln(result, line)
|
||||
LLStreamClose(stdin)
|
||||
llStreamWriteln(result, line)
|
||||
llStreamClose(stdin)
|
||||
|
||||
proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
var sub = strArg(call, "sub", 1, "")
|
||||
if len(sub) == 0: invalidPragma(call)
|
||||
var by = strArg(call, "by", 2, "")
|
||||
result = LLStreamOpen("")
|
||||
result = llStreamOpen("")
|
||||
var line = newStringOfCap(80)
|
||||
while LLStreamReadLine(stdin, line):
|
||||
LLStreamWriteln(result, replace(line, sub, by))
|
||||
LLStreamClose(stdin)
|
||||
while llStreamReadLine(stdin, line):
|
||||
llStreamWriteln(result, replace(line, sub, by))
|
||||
llStreamClose(stdin)
|
||||
|
||||
588
compiler/guards.nim
Normal file
588
compiler/guards.nim
Normal file
@@ -0,0 +1,588 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements the 'implies' relation for guards.
|
||||
|
||||
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents
|
||||
|
||||
const
|
||||
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
mEqUntracedRef, mEqStr, mEqSet, mEqCString}
|
||||
|
||||
# set excluded here as the semantics are vastly different:
|
||||
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||
mLeCh, mLeB, mLePtr, mLeStr}
|
||||
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
mLtCh, mLtB, mLtPtr, mLtStr}
|
||||
|
||||
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
|
||||
|
||||
someIn = {mInRange, mInSet}
|
||||
|
||||
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
|
||||
proc isLocation(n: PNode): bool = not n.isValue
|
||||
|
||||
proc isLet(n: PNode): bool =
|
||||
if n.kind == nkSym:
|
||||
if n.sym.kind in {skLet, skTemp, skForVar}:
|
||||
result = true
|
||||
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
||||
abstractInst).kind != tyVar:
|
||||
result = true
|
||||
|
||||
proc isVar(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.kind in {skResult, skVar} and
|
||||
{sfGlobal, sfAddrTaken} * n.sym.flags == {}
|
||||
|
||||
proc isLetLocation(m: PNode, isApprox: bool): bool =
|
||||
# consider: 'n[].kind' --> we really need to support 1 deref op even if this
|
||||
# is technically wrong due to aliasing :-( We could introduce "soft" facts
|
||||
# for this; this would still be very useful for warnings and also nicely
|
||||
# solves the 'var' problems. For now we fix this by requiring much more
|
||||
# restrictive expressions for the 'not nil' checking.
|
||||
var n = m
|
||||
var derefs = 0
|
||||
while true:
|
||||
case n.kind
|
||||
of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv:
|
||||
n = n.sons[0]
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
n = n.sons[0]
|
||||
inc derefs
|
||||
of nkBracketExpr:
|
||||
if isConstExpr(n.sons[1]) or isLet(n.sons[1]):
|
||||
n = n.sons[0]
|
||||
else: return
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
n = n.sons[1]
|
||||
else:
|
||||
break
|
||||
result = n.isLet and derefs <= ord(isApprox)
|
||||
if not result and isApprox:
|
||||
result = isVar(n)
|
||||
|
||||
proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
|
||||
|
||||
proc getMagicOp(name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
|
||||
result.magic = m
|
||||
|
||||
let
|
||||
opLe = getMagicOp("<=", mLeI)
|
||||
opLt = getMagicOp("<", mLtI)
|
||||
opAnd = getMagicOp("and", mAnd)
|
||||
opOr = getMagicOp("or", mOr)
|
||||
opNot = getMagicOp("not", mNot)
|
||||
opIsNil = getMagicOp("isnil", mIsNil)
|
||||
opContains = getMagicOp("contains", mInSet)
|
||||
opEq = getMagicOp("==", mEqI)
|
||||
|
||||
proc swapArgs(fact: PNode, newOp: PSym): PNode =
|
||||
result = newNodeI(nkCall, fact.info, 3)
|
||||
result.sons[0] = newSymNode(newOp)
|
||||
result.sons[1] = fact.sons[2]
|
||||
result.sons[2] = fact.sons[1]
|
||||
|
||||
proc neg(n: PNode): PNode =
|
||||
if n == nil: return nil
|
||||
case n.getMagic
|
||||
of mNot:
|
||||
result = n.sons[1]
|
||||
of someLt:
|
||||
# not (a < b) == a >= b == b <= a
|
||||
result = swapArgs(n, opLe)
|
||||
of someLe:
|
||||
result = swapArgs(n, opLt)
|
||||
of mInSet:
|
||||
if n.sons[1].kind != nkCurly: return nil
|
||||
let t = n.sons[2].typ.skipTypes(abstractInst)
|
||||
result = newNodeI(nkCall, n.info, 3)
|
||||
result.sons[0] = n.sons[0]
|
||||
result.sons[2] = n.sons[2]
|
||||
if t.kind == tyEnum:
|
||||
var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
|
||||
for e in t.n:
|
||||
let eAsNode = newIntNode(nkIntLit, e.sym.position)
|
||||
if not inSet(n.sons[1], eAsNode): s.add eAsNode
|
||||
result.sons[1] = s
|
||||
elif lengthOrd(t) < 1000:
|
||||
result.sons[1] = complement(n.sons[1])
|
||||
else:
|
||||
# not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4
|
||||
# XXX todo
|
||||
result = nil
|
||||
of mOr:
|
||||
# not (a or b) --> not a and not b
|
||||
let
|
||||
a = n.sons[1].neg
|
||||
b = n.sons[2].neg
|
||||
if a != nil and b != nil:
|
||||
result = newNodeI(nkCall, n.info, 3)
|
||||
result.sons[0] = newSymNode(opAnd)
|
||||
result.sons[1] = a
|
||||
result.sons[2] = b
|
||||
elif a != nil:
|
||||
result = a
|
||||
elif b != nil:
|
||||
result = b
|
||||
else:
|
||||
# leave not (a == 4) as it is
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.sons[0] = newSymNode(opNot)
|
||||
result.sons[1] = n
|
||||
|
||||
proc buildIsNil(arg: PNode): PNode =
|
||||
result = newNodeI(nkCall, arg.info, 2)
|
||||
result.sons[0] = newSymNode(opIsNil)
|
||||
result.sons[1] = arg
|
||||
|
||||
proc usefulFact(n: PNode): PNode =
|
||||
case n.getMagic
|
||||
of someEq:
|
||||
if skipConv(n.sons[2]).kind == nkNilLit and (
|
||||
isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
|
||||
result = buildIsNil(n.sons[1])
|
||||
else:
|
||||
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
|
||||
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
|
||||
result = n
|
||||
of someLe+someLt:
|
||||
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
|
||||
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
|
||||
result = n
|
||||
of mIsNil:
|
||||
if isLetLocation(n.sons[1], false) or isVar(n.sons[1]):
|
||||
result = n
|
||||
of someIn:
|
||||
if isLetLocation(n.sons[1], true):
|
||||
result = n
|
||||
of mAnd:
|
||||
let
|
||||
a = usefulFact(n.sons[1])
|
||||
b = usefulFact(n.sons[2])
|
||||
if a != nil and b != nil:
|
||||
result = newNodeI(nkCall, n.info, 3)
|
||||
result.sons[0] = newSymNode(opAnd)
|
||||
result.sons[1] = a
|
||||
result.sons[2] = b
|
||||
elif a != nil:
|
||||
result = a
|
||||
elif b != nil:
|
||||
result = b
|
||||
of mNot:
|
||||
let a = usefulFact(n.sons[1])
|
||||
if a != nil:
|
||||
result = a.neg
|
||||
of mOr:
|
||||
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
|
||||
# with that knowledge...
|
||||
# DeMorgan helps a little though:
|
||||
# not a or not b --> not (a and b)
|
||||
# (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
|
||||
# not (x != 3 and y != 2)
|
||||
let
|
||||
a = usefulFact(n.sons[1]).neg
|
||||
b = usefulFact(n.sons[2]).neg
|
||||
if a != nil and b != nil:
|
||||
result = newNodeI(nkCall, n.info, 3)
|
||||
result.sons[0] = newSymNode(opAnd)
|
||||
result.sons[1] = a
|
||||
result.sons[2] = b
|
||||
result = result.neg
|
||||
elif n.kind == nkSym and n.sym.kind == skLet:
|
||||
# consider:
|
||||
# let a = 2 < x
|
||||
# if a:
|
||||
# ...
|
||||
# We make can easily replace 'a' by '2 < x' here:
|
||||
if n.sym.ast != nil:
|
||||
result = usefulFact(n.sym.ast)
|
||||
elif n.kind == nkStmtListExpr:
|
||||
result = usefulFact(n.lastSon)
|
||||
|
||||
type
|
||||
TModel* = seq[PNode] # the "knowledge base"
|
||||
|
||||
proc addFact*(m: var TModel, n: PNode) =
|
||||
let n = usefulFact(n)
|
||||
if n != nil: m.add n
|
||||
|
||||
proc addFactNeg*(m: var TModel, n: PNode) =
|
||||
let n = n.neg
|
||||
if n != nil: addFact(m, n)
|
||||
|
||||
proc sameTree(a, b: PNode): bool =
|
||||
result = false
|
||||
if a == b:
|
||||
result = true
|
||||
elif (a != nil) and (b != nil) and (a.kind == b.kind):
|
||||
case a.kind
|
||||
of nkSym: result = a.sym == b.sym
|
||||
of nkIdent: result = a.ident.id == b.ident.id
|
||||
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
|
||||
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||
of nkType: result = a.typ == b.typ
|
||||
of nkEmpty, nkNilLit: result = true
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
if not sameTree(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
proc hasSubTree(n, x: PNode): bool =
|
||||
if n.sameTree(x): result = true
|
||||
else:
|
||||
for i in 0..safeLen(n)-1:
|
||||
if hasSubTree(n.sons[i], x): return true
|
||||
|
||||
proc invalidateFacts*(m: var TModel, n: PNode) =
|
||||
# We are able to guard local vars (as opposed to 'let' variables)!
|
||||
# 'while p != nil: f(p); p = p.next'
|
||||
# This is actually quite easy to do:
|
||||
# Re-assignments (incl. pass to a 'var' param) trigger an invalidation
|
||||
# of every fact that contains 'v'.
|
||||
#
|
||||
# if x < 4:
|
||||
# if y < 5
|
||||
# x = unknown()
|
||||
# # we invalidate 'x' here but it's known that x >= 4
|
||||
# # for the else anyway
|
||||
# else:
|
||||
# echo x
|
||||
#
|
||||
# The same mechanism could be used for more complex data stored on the heap;
|
||||
# procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
|
||||
# could CSE these expressions then and help C's optimizer.
|
||||
for i in 0..high(m):
|
||||
if m[i] != nil and m[i].hasSubTree(n): m[i] = nil
|
||||
|
||||
proc valuesUnequal(a, b: PNode): bool =
|
||||
if a.isValue and b.isValue:
|
||||
result = not sameValue(a, b)
|
||||
|
||||
proc pred(n: PNode): PNode =
|
||||
if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
|
||||
result = copyNode(n)
|
||||
dec result.intVal
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc impliesEq(fact, eq: PNode): TImplication =
|
||||
let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
|
||||
|
||||
case fact.sons[0].sym.magic
|
||||
of someEq:
|
||||
if sameTree(fact.sons[1], eq.sons[loc]):
|
||||
# this is not correct; consider: a == b; a == 1 --> unknown!
|
||||
if sameTree(fact.sons[2], eq.sons[val]): result = impYes
|
||||
elif valuesUnequal(fact.sons[2], eq.sons[val]): result = impNo
|
||||
elif sameTree(fact.sons[2], eq.sons[loc]):
|
||||
if sameTree(fact.sons[1], eq.sons[val]): result = impYes
|
||||
elif valuesUnequal(fact.sons[1], eq.sons[val]): result = impNo
|
||||
of mInSet:
|
||||
# remember: mInSet is 'contains' so the set comes first!
|
||||
if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
|
||||
if inSet(fact.sons[1], eq.sons[val]): result = impYes
|
||||
else: result = impNo
|
||||
of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
|
||||
else: discard
|
||||
|
||||
proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||
# fact: x <= 4; question x in {56}?
|
||||
# --> true if every value <= 4 is in the set {56}
|
||||
#
|
||||
var value = newIntNode(c.kind, firstOrd(x.typ))
|
||||
# don't iterate too often:
|
||||
if c.intVal - value.intVal < 1000:
|
||||
var i, pos, neg: int
|
||||
while value.intVal <= c.intVal:
|
||||
if inSet(aSet, value): inc pos
|
||||
else: inc neg
|
||||
inc i; inc value.intVal
|
||||
if pos == i: result = impYes
|
||||
elif neg == i: result = impNo
|
||||
|
||||
proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||
# fact: x >= 4; question x in {56}?
|
||||
# --> true iff every value >= 4 is in the set {56}
|
||||
#
|
||||
var value = newIntNode(c.kind, c.intVal)
|
||||
let max = lastOrd(x.typ)
|
||||
# don't iterate too often:
|
||||
if max - value.intVal < 1000:
|
||||
var i, pos, neg: int
|
||||
while value.intVal <= max:
|
||||
if inSet(aSet, value): inc pos
|
||||
else: inc neg
|
||||
inc i; inc value.intVal
|
||||
if pos == i: result = impYes
|
||||
elif neg == i: result = impNo
|
||||
|
||||
proc compareSets(a, b: PNode): TImplication =
|
||||
if equalSets(a, b): result = impYes
|
||||
elif intersectSets(a, b).len == 0: result = impNo
|
||||
|
||||
proc impliesIn(fact, loc, aSet: PNode): TImplication =
|
||||
case fact.sons[0].sym.magic
|
||||
of someEq:
|
||||
if sameTree(fact.sons[1], loc):
|
||||
if inSet(aSet, fact.sons[2]): result = impYes
|
||||
else: result = impNo
|
||||
elif sameTree(fact.sons[2], loc):
|
||||
if inSet(aSet, fact.sons[1]): result = impYes
|
||||
else: result = impNo
|
||||
of mInSet:
|
||||
if sameTree(fact.sons[2], loc):
|
||||
result = compareSets(fact.sons[1], aSet)
|
||||
of someLe:
|
||||
if sameTree(fact.sons[1], loc):
|
||||
result = leImpliesIn(fact.sons[1], fact.sons[2], aSet)
|
||||
elif sameTree(fact.sons[2], loc):
|
||||
result = geImpliesIn(fact.sons[2], fact.sons[1], aSet)
|
||||
of someLt:
|
||||
if sameTree(fact.sons[1], loc):
|
||||
result = leImpliesIn(fact.sons[1], fact.sons[2].pred, aSet)
|
||||
elif sameTree(fact.sons[2], loc):
|
||||
# 4 < x --> 3 <= x
|
||||
result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
|
||||
of mNot, mOr, mAnd: internalError(loc.info, "impliesIn")
|
||||
else: discard
|
||||
|
||||
proc valueIsNil(n: PNode): TImplication =
|
||||
if n.kind == nkNilLit: impYes
|
||||
elif n.kind in {nkStrLit..nkTripleStrLit, nkBracket, nkObjConstr}: impNo
|
||||
else: impUnknown
|
||||
|
||||
proc impliesIsNil(fact, eq: PNode): TImplication =
|
||||
case fact.sons[0].sym.magic
|
||||
of mIsNil:
|
||||
if sameTree(fact.sons[1], eq.sons[1]):
|
||||
result = impYes
|
||||
of someEq:
|
||||
if sameTree(fact.sons[1], eq.sons[1]):
|
||||
result = valueIsNil(fact.sons[2].skipConv)
|
||||
elif sameTree(fact.sons[2], eq.sons[1]):
|
||||
result = valueIsNil(fact.sons[1].skipConv)
|
||||
of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
|
||||
else: discard
|
||||
|
||||
proc impliesGe(fact, x, c: PNode): TImplication =
|
||||
internalAssert isLocation(x)
|
||||
case fact.sons[0].sym.magic
|
||||
of someEq:
|
||||
if sameTree(fact.sons[1], x):
|
||||
if isValue(fact.sons[2]) and isValue(c):
|
||||
# fact: x = 4; question x >= 56? --> true iff 4 >= 56
|
||||
if leValue(c, fact.sons[2]): result = impYes
|
||||
else: result = impNo
|
||||
elif sameTree(fact.sons[2], x):
|
||||
if isValue(fact.sons[1]) and isValue(c):
|
||||
if leValue(c, fact.sons[1]): result = impYes
|
||||
else: result = impNo
|
||||
of someLt:
|
||||
if sameTree(fact.sons[1], x):
|
||||
if isValue(fact.sons[2]) and isValue(c):
|
||||
# fact: x < 4; question N <= x? --> false iff N <= 4
|
||||
if leValue(fact.sons[2], c): result = impNo
|
||||
# fact: x < 4; question 2 <= x? --> we don't know
|
||||
elif sameTree(fact.sons[2], x):
|
||||
# fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
|
||||
if isValue(fact.sons[1]) and isValue(c):
|
||||
if leValue(c.pred, fact.sons[1]): result = impYes
|
||||
of someLe:
|
||||
if sameTree(fact.sons[1], x):
|
||||
if isValue(fact.sons[2]) and isValue(c):
|
||||
# fact: x <= 4; question x >= 56? --> false iff 4 <= 56
|
||||
if leValue(fact.sons[2], c): result = impNo
|
||||
# fact: x <= 4; question x >= 2? --> we don't know
|
||||
elif sameTree(fact.sons[2], x):
|
||||
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
|
||||
if isValue(fact.sons[1]) and isValue(c):
|
||||
if leValue(c, fact.sons[1]): result = impYes
|
||||
of mNot, mOr, mAnd: internalError(x.info, "impliesGe")
|
||||
else: discard
|
||||
|
||||
proc impliesLe(fact, x, c: PNode): TImplication =
|
||||
if not isLocation(x):
|
||||
return impliesGe(fact, c, x)
|
||||
case fact.sons[0].sym.magic
|
||||
of someEq:
|
||||
if sameTree(fact.sons[1], x):
|
||||
if isValue(fact.sons[2]) and isValue(c):
|
||||
# fact: x = 4; question x <= 56? --> true iff 4 <= 56
|
||||
if leValue(fact.sons[2], c): result = impYes
|
||||
else: result = impNo
|
||||
elif sameTree(fact.sons[2], x):
|
||||
if isValue(fact.sons[1]) and isValue(c):
|
||||
if leValue(fact.sons[1], c): result = impYes
|
||||
else: result = impNo
|
||||
of someLt:
|
||||
if sameTree(fact.sons[1], x):
|
||||
if isValue(fact.sons[2]) and isValue(c):
|
||||
# fact: x < 4; question x <= N? --> true iff N-1 <= 4
|
||||
if leValue(fact.sons[2], c.pred): result = impYes
|
||||
# fact: x < 4; question x <= 2? --> we don't know
|
||||
elif sameTree(fact.sons[2], x):
|
||||
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
|
||||
if isValue(fact.sons[1]) and isValue(c):
|
||||
if leValue(c, fact.sons[1]): result = impNo
|
||||
|
||||
of someLe:
|
||||
if sameTree(fact.sons[1], x):
|
||||
if isValue(fact.sons[2]) and isValue(c):
|
||||
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
|
||||
if leValue(fact.sons[2], c): result = impYes
|
||||
# fact: x <= 4; question x <= 2? --> we don't know
|
||||
|
||||
elif sameTree(fact.sons[2], x):
|
||||
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
|
||||
if isValue(fact.sons[1]) and isValue(c):
|
||||
if leValue(c, fact.sons[1].pred): result = impNo
|
||||
|
||||
of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
|
||||
else: discard
|
||||
|
||||
proc impliesLt(fact, x, c: PNode): TImplication =
|
||||
# x < 3 same as x <= 2:
|
||||
let p = c.pred
|
||||
if p != c:
|
||||
result = impliesLe(fact, x, p)
|
||||
else:
|
||||
# 4 < x same as 3 <= x
|
||||
let q = x.pred
|
||||
if q != x:
|
||||
result = impliesLe(fact, q, c)
|
||||
|
||||
proc `~`(x: TImplication): TImplication =
|
||||
case x
|
||||
of impUnknown: impUnknown
|
||||
of impNo: impYes
|
||||
of impYes: impNo
|
||||
|
||||
proc factImplies(fact, prop: PNode): TImplication =
|
||||
case fact.getMagic
|
||||
of mNot:
|
||||
# Consider:
|
||||
# enum nkBinary, nkTernary, nkStr
|
||||
# fact: not (k <= nkBinary)
|
||||
# question: k in {nkStr}
|
||||
# --> 'not' for facts is entirely different than 'not' for questions!
|
||||
# it's provably wrong if every value > 4 is in the set {56}
|
||||
# That's because we compute the implication and 'a -> not b' cannot
|
||||
# be treated the same as 'not a -> b'
|
||||
|
||||
# (not a) -> b compute as not (a -> b) ???
|
||||
# == not a or not b == not (a and b)
|
||||
let arg = fact.sons[1]
|
||||
case arg.getMagic
|
||||
of mIsNil:
|
||||
return ~factImplies(arg, prop)
|
||||
of mAnd:
|
||||
# not (a and b) means not a or not b:
|
||||
# a or b --> both need to imply 'prop'
|
||||
let a = factImplies(arg.sons[1], prop)
|
||||
let b = factImplies(arg.sons[2], prop)
|
||||
if a == b: return ~a
|
||||
return impUnknown
|
||||
else:
|
||||
internalError(fact.info, "invalid fact")
|
||||
of mAnd:
|
||||
result = factImplies(fact.sons[1], prop)
|
||||
if result != impUnknown: return result
|
||||
return factImplies(fact.sons[2], prop)
|
||||
else: discard
|
||||
|
||||
case prop.sons[0].sym.magic
|
||||
of mNot: result = ~fact.factImplies(prop.sons[1])
|
||||
of mIsNil: result = impliesIsNil(fact, prop)
|
||||
of someEq: result = impliesEq(fact, prop)
|
||||
of someLe: result = impliesLe(fact, prop.sons[1], prop.sons[2])
|
||||
of someLt: result = impliesLt(fact, prop.sons[1], prop.sons[2])
|
||||
of mInSet: result = impliesIn(fact, prop.sons[2], prop.sons[1])
|
||||
else: internalError(prop.info, "invalid proposition")
|
||||
|
||||
proc doesImply*(facts: TModel, prop: PNode): TImplication =
|
||||
assert prop.kind in nkCallKinds
|
||||
for f in facts:
|
||||
# facts can be invalidated, in which case they are 'nil':
|
||||
if not f.isNil:
|
||||
result = f.factImplies(prop)
|
||||
if result != impUnknown: return
|
||||
|
||||
proc impliesNotNil*(facts: TModel, arg: PNode): TImplication =
|
||||
result = doesImply(facts, buildIsNil(arg).neg)
|
||||
|
||||
proc settype(n: PNode): PType =
|
||||
result = newType(tySet, n.typ.owner)
|
||||
addSonSkipIntLit(result, n.typ)
|
||||
|
||||
proc buildOf(it, loc: PNode): PNode =
|
||||
var s = newNodeI(nkCurly, it.info, it.len-1)
|
||||
s.typ = settype(loc)
|
||||
for i in 0..it.len-2: s.sons[i] = it.sons[i]
|
||||
result = newNodeI(nkCall, it.info, 3)
|
||||
result.sons[0] = newSymNode(opContains)
|
||||
result.sons[1] = s
|
||||
result.sons[2] = loc
|
||||
|
||||
proc buildElse(n: PNode): 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])
|
||||
result = newNodeI(nkCall, n.info, 3)
|
||||
result.sons[0] = newSymNode(opContains)
|
||||
result.sons[1] = s
|
||||
result.sons[2] = n.sons[0]
|
||||
|
||||
proc addDiscriminantFact*(m: var TModel, n: PNode) =
|
||||
var fact = newNodeI(nkCall, n.info, 3)
|
||||
fact.sons[0] = newSymNode(opEq)
|
||||
fact.sons[1] = n.sons[0]
|
||||
fact.sons[2] = n.sons[1]
|
||||
m.add fact
|
||||
|
||||
proc addAsgnFact*(m: var TModel, key, value: PNode) =
|
||||
var fact = newNodeI(nkCall, key.info, 3)
|
||||
fact.sons[0] = newSymNode(opEq)
|
||||
fact.sons[1] = key
|
||||
fact.sons[2] = value
|
||||
m.add fact
|
||||
|
||||
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
|
||||
let branch = n.sons[i]
|
||||
if branch.kind == nkOfBranch:
|
||||
m.add buildOf(branch, n.sons[0])
|
||||
else:
|
||||
m.add n.buildElse.neg
|
||||
|
||||
proc buildProperFieldCheck(access, check: PNode): PNode =
|
||||
if check.sons[1].kind == nkCurly:
|
||||
result = copyTree(check)
|
||||
if access.kind == nkDotExpr:
|
||||
var a = copyTree(access)
|
||||
a.sons[1] = check.sons[2]
|
||||
result.sons[2] = a
|
||||
# 'access.kind != nkDotExpr' can happen for object constructors
|
||||
# which we don't check yet
|
||||
else:
|
||||
# it is some 'not'
|
||||
assert check.getMagic == mNot
|
||||
result = buildProperFieldCheck(access, check.sons[1]).neg
|
||||
|
||||
proc checkFieldAccess*(m: TModel, n: PNode) =
|
||||
for i in 1..n.len-1:
|
||||
let check = buildProperFieldCheck(n.sons[0], n.sons[i])
|
||||
if m.doesImply(check) != impYes:
|
||||
message(n.info, warnProveField, renderTree(n.sons[0])); break
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -12,7 +12,7 @@
|
||||
proc hlo(c: PContext, n: PNode): PNode
|
||||
|
||||
proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym
|
||||
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
|
||||
# we need to ensure that the resulting AST is semchecked. However, it's
|
||||
# aweful to semcheck before macro invocation, so we don't and treat
|
||||
# templates and macros as immediate in this context.
|
||||
@@ -28,10 +28,8 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
else:
|
||||
result = semDirectOp(c, n, {})
|
||||
if optHints in gOptions and hintPattern in gNotes:
|
||||
Message(orig.info, hintPattern, rule & " --> '" &
|
||||
message(orig.info, hintPattern, rule & " --> '" &
|
||||
renderTree(result, {renderNoComments}) & "'")
|
||||
# check the resulting AST for optimization rules again:
|
||||
result = hlo(c, result)
|
||||
|
||||
proc applyPatterns(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -44,9 +42,10 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
|
||||
let x = applyRule(c, pattern, result)
|
||||
if not isNil(x):
|
||||
assert x.kind in {nkStmtList, nkCall}
|
||||
# better be safe than sorry, so check evalTemplateCounter too:
|
||||
inc(evalTemplateCounter)
|
||||
if evalTemplateCounter > 100:
|
||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||
globalError(n.info, errTemplateInstantiationTooNested)
|
||||
# deactivate this pattern:
|
||||
c.patterns[i] = nil
|
||||
if x.kind == nkStmtList:
|
||||
@@ -60,11 +59,19 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
|
||||
c.patterns[i] = pattern
|
||||
|
||||
proc hlo(c: PContext, n: PNode): PNode =
|
||||
inc(c.hloLoopDetector)
|
||||
# simply stop and do not perform any further transformations:
|
||||
if c.hloLoopDetector > 300: return n
|
||||
case n.kind
|
||||
of nkMacroDef, nkTemplateDef, procDefs:
|
||||
# already processed (special cases in semstmts.nim)
|
||||
result = n
|
||||
else:
|
||||
if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
|
||||
n.sons[0].kind == nkSym and
|
||||
{sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
|
||||
# do not optimize 'var g {.global} = re(...)' again!
|
||||
return n
|
||||
result = applyPatterns(c, n)
|
||||
if result == n:
|
||||
# no optimization applied, try subtrees:
|
||||
@@ -74,18 +81,23 @@ proc hlo(c: PContext, n: PNode): PNode =
|
||||
if h != a: result.sons[i] = h
|
||||
else:
|
||||
# perform type checking, so that the replacement still fits:
|
||||
if n.typ == nil and (result.typ == nil or
|
||||
result.typ.kind in {tyStmt, tyEmpty}):
|
||||
nil
|
||||
if isEmptyType(n.typ) and isEmptyType(result.typ):
|
||||
discard
|
||||
else:
|
||||
result = fitNode(c, n.typ, result)
|
||||
# optimization has been applied so check again:
|
||||
result = commonOptimizations(c.module, result)
|
||||
result = hlo(c, result)
|
||||
result = commonOptimizations(c.module, result)
|
||||
|
||||
proc hloBody(c: PContext, n: PNode): PNode =
|
||||
# fast exit:
|
||||
if c.patterns.len == 0 or optPatterns notin gOptions: return n
|
||||
c.hloLoopDetector = 0
|
||||
result = hlo(c, n)
|
||||
|
||||
proc hloStmt(c: PContext, n: PNode): PNode =
|
||||
# fast exit:
|
||||
if c.patterns.len == 0 or optPatterns notin gOptions: return n
|
||||
c.hloLoopDetector = 0
|
||||
result = hlo(c, n)
|
||||
|
||||
@@ -24,10 +24,13 @@ type
|
||||
s*: string
|
||||
next*: PIdent # for hash-table chaining
|
||||
h*: THash # hash value of s
|
||||
|
||||
|
||||
var firstCharIsCS*: bool
|
||||
var buckets*: array[0..4096 * 2 - 1, PIdent]
|
||||
|
||||
proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
|
||||
if firstCharIsCS:
|
||||
if a[0] != b[0]: return 1
|
||||
var i = 0
|
||||
var j = 0
|
||||
result = 1
|
||||
@@ -99,8 +102,9 @@ proc getIdent*(identifier: string): PIdent =
|
||||
proc getIdent*(identifier: string, h: THash): PIdent =
|
||||
result = getIdent(cstring(identifier), len(identifier), h)
|
||||
|
||||
proc IdentEq*(id: PIdent, name: string): bool =
|
||||
proc identEq*(id: PIdent, name: string): bool =
|
||||
result = id.id == getIdent(name).id
|
||||
|
||||
var idAnon* = getIdent":anonymous"
|
||||
let idDelegator* = getIdent":delegator"
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ const
|
||||
when debugIds:
|
||||
import intsets
|
||||
|
||||
var usedIds = InitIntSet()
|
||||
var usedIds = initIntSet()
|
||||
|
||||
proc registerID*(id: PIdObj) =
|
||||
when debugIDs:
|
||||
if id.id == -1 or ContainsOrIncl(usedIds, id.id):
|
||||
InternalError("ID already used: " & $id.id)
|
||||
when debugIds:
|
||||
if id.id == -1 or containsOrIncl(usedIds, id.id):
|
||||
internalError("ID already used: " & $id.id)
|
||||
|
||||
proc getID*(): int {.inline.} =
|
||||
result = gFrontEndId
|
||||
@@ -37,8 +37,8 @@ proc backendId*(): int {.inline.} =
|
||||
proc setId*(id: int) {.inline.} =
|
||||
gFrontEndId = max(gFrontEndId, id + 1)
|
||||
|
||||
proc IDsynchronizationPoint*(idRange: int) =
|
||||
gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1
|
||||
proc idSynchronizationPoint*(idRange: int) =
|
||||
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
|
||||
|
||||
proc toGid(f: string): string =
|
||||
# we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
|
||||
@@ -49,7 +49,7 @@ proc toGid(f: string): string =
|
||||
proc saveMaxIds*(project: string) =
|
||||
var f = open(project.toGid, fmWrite)
|
||||
f.writeln($gFrontEndId)
|
||||
f.writeln($gBackEndId)
|
||||
f.writeln($gBackendId)
|
||||
f.close()
|
||||
|
||||
proc loadMaxIds*(project: string) =
|
||||
@@ -61,5 +61,5 @@ proc loadMaxIds*(project: string) =
|
||||
if f.readLine(line):
|
||||
var backEndId = parseInt(line)
|
||||
gFrontEndId = max(gFrontEndId, frontEndId)
|
||||
gBackEndId = max(gBackEndId, backEndId)
|
||||
gBackendId = max(gBackendId, backEndId)
|
||||
f.close()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -22,24 +22,35 @@ proc getModuleName*(n: PNode): string =
|
||||
# The proc won't perform any checks that the path is actually valid
|
||||
case n.kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
result = UnixToNativePath(n.strVal)
|
||||
result = unixToNativePath(n.strVal)
|
||||
of nkIdent:
|
||||
result = n.ident.s
|
||||
of nkSym:
|
||||
result = n.sym.name.s
|
||||
else:
|
||||
of nkInfix:
|
||||
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
|
||||
# XXX hack ahead:
|
||||
n.kind = nkImportAs
|
||||
n.sons[0] = n.sons[1]
|
||||
n.sons[1] = n.sons[2]
|
||||
n.sons.setLen(2)
|
||||
return getModuleName(n.sons[0])
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = renderTree(n, {renderNoComments}).replace(" ")
|
||||
#localError(n.info, errGenerated,
|
||||
# "invalide module name: '$1'" % renderTree(n))
|
||||
#result = ""
|
||||
of nkDotExpr:
|
||||
result = renderTree(n, {renderNoComments}).replace(".", "/")
|
||||
of nkImportAs:
|
||||
result = getModuleName(n.sons[0])
|
||||
else:
|
||||
localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
|
||||
result = ""
|
||||
|
||||
proc checkModuleName*(n: PNode): int32 =
|
||||
# This returns the full canonical path for a given module import
|
||||
let modulename = n.getModuleName
|
||||
let fullPath = findModule(modulename)
|
||||
let fullPath = findModule(modulename, n.info.toFullPath)
|
||||
if fullPath.len == 0:
|
||||
LocalError(n.info, errCannotOpenFile, modulename)
|
||||
localError(n.info, errCannotOpenFile, modulename)
|
||||
result = InvalidFileIDX
|
||||
else:
|
||||
result = fullPath.fileInfoIdx
|
||||
@@ -48,32 +59,32 @@ proc rawImportSymbol(c: PContext, s: 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:
|
||||
var check = StrTableGet(c.importTable.symbols, s.name)
|
||||
var check = strTableGet(c.importTable.symbols, s.name)
|
||||
if check != nil and check.id != s.id:
|
||||
if s.kind notin OverloadableSyms:
|
||||
# s and check need to be qualified:
|
||||
Incl(c.AmbiguousSymbols, s.id)
|
||||
Incl(c.AmbiguousSymbols, check.id)
|
||||
incl(c.ambiguousSymbols, s.id)
|
||||
incl(c.ambiguousSymbols, check.id)
|
||||
# thanks to 'export' feature, it could be we import the same symbol from
|
||||
# multiple sources, so we need to call 'StrTableAdd' here:
|
||||
StrTableAdd(c.importTable.symbols, s)
|
||||
strTableAdd(c.importTable.symbols, s)
|
||||
if s.kind == skType:
|
||||
var etyp = s.typ
|
||||
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
|
||||
for j in countup(0, sonsLen(etyp.n) - 1):
|
||||
var e = etyp.n.sons[j].sym
|
||||
if e.Kind != skEnumField:
|
||||
InternalError(s.info, "rawImportSymbol")
|
||||
if e.kind != skEnumField:
|
||||
internalError(s.info, "rawImportSymbol")
|
||||
# BUGFIX: because of aliases for enums the symbol may already
|
||||
# have been put into the symbol table
|
||||
# BUGFIX: but only iff they are the same symbols!
|
||||
var it: TIdentIter
|
||||
check = InitIdentIter(it, c.importTable.symbols, e.name)
|
||||
check = initIdentIter(it, c.importTable.symbols, e.name)
|
||||
while check != nil:
|
||||
if check.id == e.id:
|
||||
e = nil
|
||||
break
|
||||
check = NextIdentIter(it, c.importTable.symbols)
|
||||
check = nextIdentIter(it, c.importTable.symbols)
|
||||
if e != nil:
|
||||
rawImportSymbol(c, e)
|
||||
else:
|
||||
@@ -83,36 +94,36 @@ proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
|
||||
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
let ident = lookups.considerAcc(n)
|
||||
let s = StrTableGet(fromMod.tab, ident)
|
||||
let s = strTableGet(fromMod.tab, ident)
|
||||
if s == nil:
|
||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
else:
|
||||
if s.kind == skStub: loadStub(s)
|
||||
if s.Kind notin ExportableSymKinds:
|
||||
InternalError(n.info, "importSymbol: 2")
|
||||
if s.kind notin ExportableSymKinds:
|
||||
internalError(n.info, "importSymbol: 2")
|
||||
# for an enumeration we have to add all identifiers
|
||||
case s.Kind
|
||||
of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter:
|
||||
case s.kind
|
||||
of skProcKinds:
|
||||
# for a overloadable syms add all overloaded routines
|
||||
var it: TIdentIter
|
||||
var e = InitIdentIter(it, fromMod.tab, s.name)
|
||||
var e = initIdentIter(it, fromMod.tab, s.name)
|
||||
while e != nil:
|
||||
if e.name.id != s.Name.id: InternalError(n.info, "importSymbol: 3")
|
||||
if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
|
||||
rawImportSymbol(c, e)
|
||||
e = NextIdentIter(it, fromMod.tab)
|
||||
e = nextIdentIter(it, fromMod.tab)
|
||||
else: rawImportSymbol(c, s)
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
||||
var i: TTabIter
|
||||
var s = InitTabIter(i, fromMod.tab)
|
||||
var s = initTabIter(i, fromMod.tab)
|
||||
while s != nil:
|
||||
if s.kind != skModule:
|
||||
if s.kind != skEnumField:
|
||||
if s.Kind notin ExportableSymKinds:
|
||||
InternalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
if s.kind notin ExportableSymKinds:
|
||||
internalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
if exceptSet.empty or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
s = NextIter(i, fromMod.tab)
|
||||
s = nextIter(i, fromMod.tab)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
var exceptSet: TIntSet
|
||||
@@ -135,15 +146,28 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
|
||||
for i in 0 ..safeLen(n)-1:
|
||||
importForwarded(c, n.sons[i], exceptSet)
|
||||
|
||||
proc importModuleAs(n: PNode, realModule: PSym): PSym =
|
||||
result = realModule
|
||||
if n.kind != nkImportAs: discard
|
||||
elif n.len != 2 or n.sons[1].kind != nkIdent:
|
||||
localError(n.info, errGenerated, "module alias must be an identifier")
|
||||
elif n.sons[1].ident.id != realModule.name.id:
|
||||
# some misguided guy will write 'import abc.foo as foo' ...
|
||||
result = createModuleAlias(realModule, n.sons[1].ident, n.sons[1].info)
|
||||
|
||||
proc myImportModule(c: PContext, n: PNode): PSym =
|
||||
var f = checkModuleName(n)
|
||||
if f != InvalidFileIDX:
|
||||
result = importModuleAs(n, gImportModule(c.module, f))
|
||||
if sfDeprecated in result.flags:
|
||||
message(n.info, warnDeprecated, result.name.s)
|
||||
|
||||
proc evalImport(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var emptySet: TIntSet
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var f = checkModuleName(n.sons[i])
|
||||
if f != InvalidFileIDX:
|
||||
var m = gImportModule(c.module, f)
|
||||
if sfDeprecated in m.flags:
|
||||
Message(n.sons[i].info, warnDeprecated, m.name.s)
|
||||
var m = myImportModule(c, n.sons[i])
|
||||
if m != nil:
|
||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
importAllSymbolsExcept(c, m, emptySet)
|
||||
@@ -152,21 +176,19 @@ proc evalImport(c: PContext, n: PNode): PNode =
|
||||
proc evalFrom(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 2)
|
||||
var f = checkModuleName(n.sons[0])
|
||||
if f != InvalidFileIDX:
|
||||
var m = gImportModule(c.module, f)
|
||||
var m = myImportModule(c, n.sons[0])
|
||||
if m != nil:
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkNilLit:
|
||||
importSymbol(c, n.sons[i], m)
|
||||
|
||||
proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 2)
|
||||
var f = checkModuleName(n.sons[0])
|
||||
if f != InvalidFileIDX:
|
||||
var m = gImportModule(c.module, f)
|
||||
var m = myImportModule(c, n.sons[0])
|
||||
if m != nil:
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
var exceptSet = initIntSet()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope =
|
||||
[mangleName(field), s, makeJSString(field.name.s)])
|
||||
of nkRecCase:
|
||||
length = sonsLen(n)
|
||||
if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields")
|
||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
|
||||
field = n.sons[0].sym
|
||||
s = genTypeInfo(p, field.typ)
|
||||
for i in countup(1, length - 1):
|
||||
@@ -98,7 +98,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
|
||||
let length = sonsLen(typ.n)
|
||||
var s: PRope = nil
|
||||
for i in countup(0, length - 1):
|
||||
if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
|
||||
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
|
||||
let field = typ.n.sons[i].sym
|
||||
if i > 0: app(s, ", " & tnl)
|
||||
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
|
||||
@@ -119,7 +119,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
|
||||
var t = typ
|
||||
if t.kind == tyGenericInst: t = lastSon(t)
|
||||
result = ropef("NTI$1", [toRope(t.id)])
|
||||
if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return
|
||||
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
||||
case t.kind
|
||||
of tyDistinct:
|
||||
result = genTypeInfo(p, typ.sons[0])
|
||||
@@ -134,7 +134,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
|
||||
[result, toRope(ord(t.kind))])
|
||||
prepend(p.g.typeInfo, s)
|
||||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[result, genTypeInfo(p, typ.sons[0])])
|
||||
[result, genTypeInfo(p, typ.lastSon)])
|
||||
of tyArrayConstr, tyArray:
|
||||
var s = ropef(
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
|
||||
@@ -145,4 +145,4 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
|
||||
of tyEnum: genEnumInfo(p, t, result)
|
||||
of tyObject: genObjectInfo(p, t, result)
|
||||
of tyTuple: genTupleInfo(p, t, result)
|
||||
else: InternalError("genTypeInfo(" & $t.kind & ')')
|
||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, magicsys, rodread
|
||||
idents, renderer, types, magicsys, rodread, lowerings
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
@@ -116,98 +116,58 @@ type
|
||||
TDep = tuple[e: PEnv, field: PSym]
|
||||
TEnv {.final.} = object of TObject
|
||||
attachedNode: PNode
|
||||
closure: PSym # if != nil it is a used environment
|
||||
createdVar: PSym # if != nil it is a used environment
|
||||
createdVarComesFromIter: bool
|
||||
capturedVars: seq[PSym] # captured variables in this environment
|
||||
deps: seq[TDep] # dependencies
|
||||
deps: seq[TDep] # dependencies
|
||||
up: PEnv
|
||||
tup: PType
|
||||
obj: PType
|
||||
|
||||
TInnerContext {.final.} = object
|
||||
TInnerContext = object
|
||||
fn: PSym
|
||||
closureParam: PSym
|
||||
localsToAccess: TIdNodeTable
|
||||
|
||||
TOuterContext {.final.} = object
|
||||
TOuterContext = object
|
||||
fn: PSym # may also be a module!
|
||||
currentEnv: PEnv
|
||||
isIter: bool # first class iterator?
|
||||
capturedVars, processed: TIntSet
|
||||
localsToEnv: TIdTable # PSym->PEnv mapping
|
||||
localsToAccess: TIdNodeTable
|
||||
lambdasToEnv: TIdTable # PSym->PEnv mapping
|
||||
up: POuterContext
|
||||
|
||||
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
|
||||
new(result)
|
||||
result.fn = fn
|
||||
result.capturedVars = initIntSet()
|
||||
result.processed = initIntSet()
|
||||
initIdNodeTable(result.localsToAccess)
|
||||
initIdTable(result.localsToEnv)
|
||||
initIdTable(result.lambdasToEnv)
|
||||
|
||||
proc newInnerContext(fn: PSym): PInnerContext =
|
||||
new(result)
|
||||
result.fn = fn
|
||||
initIdNodeTable(result.localsToAccess)
|
||||
|
||||
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
|
||||
new(result)
|
||||
result.deps = @[]
|
||||
result.capturedVars = @[]
|
||||
result.tup = newType(tyTuple, outerProc)
|
||||
result.tup.n = newNodeI(nkRecList, outerProc.info)
|
||||
result.up = up
|
||||
result.attachedNode = n
|
||||
closureParam, state, resultSym: PSym # only if isIter
|
||||
obj: PType # only if isIter
|
||||
|
||||
proc addField(tup: PType, s: PSym) =
|
||||
var field = newSym(skField, s.name, s.owner, s.info)
|
||||
let t = skipIntLit(s.typ)
|
||||
field.typ = t
|
||||
field.position = sonsLen(tup)
|
||||
addSon(tup.n, newSymNode(field))
|
||||
rawAddSon(tup, t)
|
||||
|
||||
proc addCapturedVar(e: PEnv, v: PSym) =
|
||||
for x in e.capturedVars:
|
||||
if x == v: return
|
||||
e.capturedVars.add(v)
|
||||
addField(e.tup, v)
|
||||
|
||||
proc addDep(e, d: PEnv, owner: PSym): PSym =
|
||||
for x, field in items(e.deps):
|
||||
if x == d: return field
|
||||
var pos = sonsLen(e.tup)
|
||||
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
|
||||
result.typ = newType(tyRef, owner)
|
||||
result.position = pos
|
||||
assert d.tup != nil
|
||||
rawAddSon(result.typ, d.tup)
|
||||
addField(e.tup, result)
|
||||
e.deps.add((d, result))
|
||||
|
||||
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||
# returns a[].b as a node
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = a.typ.sons[0]
|
||||
let field = getSymFromList(deref.typ.n, b.name)
|
||||
assert field != nil, b.name.s
|
||||
addSon(deref, a)
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
addSon(result, deref)
|
||||
addSon(result, newSymNode(field))
|
||||
result.typ = field.typ
|
||||
proc getStateType(iter: PSym): PType =
|
||||
var n = newNodeI(nkRange, iter.info)
|
||||
addSon(n, newIntNode(nkIntLit, -1))
|
||||
addSon(n, newIntNode(nkIntLit, 0))
|
||||
result = newType(tyRange, iter)
|
||||
result.n = n
|
||||
rawAddSon(result, getSysType(tyInt))
|
||||
|
||||
proc indirectAccess(a, b: PSym, info: TLineInfo): PNode =
|
||||
result = indirectAccess(newSymNode(a), b, info)
|
||||
proc createStateField(iter: PSym): PSym =
|
||||
result = newSym(skField, getIdent(":state"), iter, iter.info)
|
||||
result.typ = getStateType(iter)
|
||||
|
||||
proc newCall(a, b: PSym): PNode =
|
||||
result = newNodeI(nkCall, a.info)
|
||||
result.add newSymNode(a)
|
||||
result.add newSymNode(b)
|
||||
proc newIterResult(iter: PSym): PSym =
|
||||
if resultPos < iter.ast.len:
|
||||
result = iter.ast.sons[resultPos].sym
|
||||
else:
|
||||
# XXX a bit hacky:
|
||||
result = newSym(skResult, getIdent":result", iter, iter.info)
|
||||
result.typ = iter.typ.sons[0]
|
||||
incl(result.flags, sfUsed)
|
||||
iter.ast.add newSymNode(result)
|
||||
|
||||
proc addHiddenParam(routine: PSym, param: PSym) =
|
||||
var params = routine.ast.sons[paramsPos]
|
||||
param.position = params.len
|
||||
# -1 is correct here as param.position is 0 based but we have at position 0
|
||||
# some nkEffect node:
|
||||
param.position = params.len-1
|
||||
addSon(params, newSymNode(param))
|
||||
incl(routine.typ.flags, tfCapturesEnv)
|
||||
#echo "produced environment: ", param.id, " for ", routine.name.s
|
||||
@@ -218,24 +178,115 @@ proc getHiddenParam(routine: PSym): PSym =
|
||||
assert hidden.kind == nkSym
|
||||
result = hidden.sym
|
||||
|
||||
proc getEnvParam(routine: PSym): PSym =
|
||||
let params = routine.ast.sons[paramsPos]
|
||||
let hidden = lastSon(params)
|
||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||
result = hidden.sym
|
||||
|
||||
proc initIterContext(c: POuterContext, iter: PSym) =
|
||||
c.fn = iter
|
||||
c.capturedVars = initIntSet()
|
||||
|
||||
var cp = getEnvParam(iter)
|
||||
if cp == nil:
|
||||
c.obj = createObj(iter, iter.info)
|
||||
|
||||
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = newType(tyRef, iter)
|
||||
rawAddSon(cp.typ, c.obj)
|
||||
addHiddenParam(iter, cp)
|
||||
|
||||
c.state = createStateField(iter)
|
||||
addField(c.obj, c.state)
|
||||
else:
|
||||
c.obj = cp.typ.sons[0]
|
||||
assert c.obj.kind == tyObject
|
||||
if c.obj.n.len > 0:
|
||||
c.state = c.obj.n[0].sym
|
||||
else:
|
||||
c.state = createStateField(iter)
|
||||
addField(c.obj, c.state)
|
||||
|
||||
c.closureParam = cp
|
||||
if iter.typ.sons[0] != nil:
|
||||
c.resultSym = newIterResult(iter)
|
||||
#iter.ast.add(newSymNode(c.resultSym))
|
||||
|
||||
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
|
||||
new(result)
|
||||
result.fn = fn
|
||||
result.capturedVars = initIntSet()
|
||||
result.processed = initIntSet()
|
||||
initIdNodeTable(result.localsToAccess)
|
||||
initIdTable(result.localsToEnv)
|
||||
initIdTable(result.lambdasToEnv)
|
||||
result.isIter = fn.kind == skClosureIterator
|
||||
if result.isIter: initIterContext(result, fn)
|
||||
|
||||
proc newInnerContext(fn: PSym): PInnerContext =
|
||||
new(result)
|
||||
result.fn = fn
|
||||
initIdNodeTable(result.localsToAccess)
|
||||
|
||||
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
|
||||
new(result)
|
||||
result.deps = @[]
|
||||
result.capturedVars = @[]
|
||||
result.obj = createObj(outerProc, outerProc.info)
|
||||
result.up = up
|
||||
result.attachedNode = n
|
||||
|
||||
proc addCapturedVar(e: PEnv, v: PSym) =
|
||||
for x in e.capturedVars:
|
||||
if x == v: return
|
||||
# XXX meh, just add the state field for every closure for now, it's too
|
||||
# hard to figure out if it comes from a closure iterator:
|
||||
if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner))
|
||||
e.capturedVars.add(v)
|
||||
addField(e.obj, v)
|
||||
|
||||
proc addDep(e, d: PEnv, owner: PSym): PSym =
|
||||
for x, field in items(e.deps):
|
||||
if x == d: return field
|
||||
var pos = sonsLen(e.obj.n)
|
||||
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
|
||||
result.typ = newType(tyRef, owner)
|
||||
result.position = pos
|
||||
assert d.obj != nil
|
||||
rawAddSon(result.typ, d.obj)
|
||||
addField(e.obj, result)
|
||||
e.deps.add((d, result))
|
||||
|
||||
proc newCall(a, b: PSym): PNode =
|
||||
result = newNodeI(nkCall, a.info)
|
||||
result.add newSymNode(a)
|
||||
result.add newSymNode(b)
|
||||
|
||||
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
|
||||
result = s.kind in {skProc, skMethod, skConverter} and
|
||||
s.owner == outerProc and not isGenericRoutine(s)
|
||||
result = s.kind in {skProc, skMethod, skConverter, skClosureIterator} and
|
||||
s.skipGenericOwner == outerProc
|
||||
#s.typ.callConv == ccClosure
|
||||
|
||||
proc addClosureParam(i: PInnerContext, e: PEnv) =
|
||||
var cp = newSym(skParam, getIdent(paramname), i.fn, i.fn.info)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = newType(tyRef, i.fn)
|
||||
rawAddSon(cp.typ, e.tup)
|
||||
var cp = getEnvParam(i.fn)
|
||||
if cp == nil:
|
||||
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = newType(tyRef, i.fn)
|
||||
rawAddSon(cp.typ, e.obj)
|
||||
addHiddenParam(i.fn, cp)
|
||||
else:
|
||||
e.obj = cp.typ.sons[0]
|
||||
assert e.obj.kind == tyObject
|
||||
i.closureParam = cp
|
||||
addHiddenParam(i.fn, i.closureParam)
|
||||
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
|
||||
|
||||
proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
|
||||
var e = o.currentEnv
|
||||
if IdTableGet(o.lambdasToEnv, i.fn) == nil:
|
||||
IdTablePut(o.lambdasToEnv, i.fn, e)
|
||||
if idTableGet(o.lambdasToEnv, i.fn) == nil:
|
||||
idTablePut(o.lambdasToEnv, i.fn, e)
|
||||
if i.closureParam == nil: addClosureParam(i, e)
|
||||
|
||||
proc illegalCapture(s: PSym): bool {.inline.} =
|
||||
@@ -247,13 +298,13 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
|
||||
info: TLineInfo) =
|
||||
# for inlined variables the owner is still wrong, so it can happen that it's
|
||||
# not a captured variable at all ... *sigh*
|
||||
var it = PEnv(IdTableGet(o.localsToEnv, local))
|
||||
var it = PEnv(idTableGet(o.localsToEnv, local))
|
||||
if it == nil: return
|
||||
|
||||
if illegalCapture(local) or o.fn.id != local.owner.id or
|
||||
i.fn.typ.callConv notin {ccClosure, ccDefault}:
|
||||
# Currently captures are restricted to a single level of nesting:
|
||||
LocalError(info, errIllegalCaptureX, local.name.s)
|
||||
localError(info, errIllegalCaptureX, local.name.s)
|
||||
i.fn.typ.callConv = ccClosure
|
||||
#echo "captureVar ", i.fn.name.s, i.fn.id, " ", local.name.s, local.id
|
||||
|
||||
@@ -261,11 +312,11 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
|
||||
|
||||
# we need to remember which inner most closure belongs to this lambda:
|
||||
var e = o.currentEnv
|
||||
if IdTableGet(o.lambdasToEnv, i.fn) == nil:
|
||||
IdTablePut(o.lambdasToEnv, i.fn, e)
|
||||
if idTableGet(o.lambdasToEnv, i.fn) == nil:
|
||||
idTablePut(o.lambdasToEnv, i.fn, e)
|
||||
|
||||
# variable already captured:
|
||||
if IdNodeTableGet(i.localsToAccess, local) != nil: return
|
||||
if idNodeTableGet(i.localsToAccess, local) != nil: return
|
||||
if i.closureParam == nil: addClosureParam(i, e)
|
||||
|
||||
# check which environment `local` belongs to:
|
||||
@@ -273,13 +324,16 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
|
||||
addCapturedVar(it, local)
|
||||
if it == e:
|
||||
# common case: local directly in current environment:
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
# it's in some upper environment:
|
||||
access = indirectAccess(access, addDep(e, it, i.fn), info)
|
||||
access = indirectAccess(access, local, info)
|
||||
incl(o.capturedVars, local.id)
|
||||
IdNodeTablePut(i.localsToAccess, local, access)
|
||||
if o.isIter:
|
||||
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
|
||||
else:
|
||||
incl(o.capturedVars, local.id)
|
||||
idNodeTablePut(i.localsToAccess, local, access)
|
||||
|
||||
proc interestingVar(s: PSym): bool {.inline.} =
|
||||
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
|
||||
@@ -288,6 +342,9 @@ proc interestingVar(s: PSym): bool {.inline.} =
|
||||
proc semCaptureSym*(s, owner: PSym) =
|
||||
if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
|
||||
if owner.typ != nil and not isGenericRoutine(owner):
|
||||
# XXX: is this really safe?
|
||||
# if we capture a var from another generic routine,
|
||||
# it won't be consider captured.
|
||||
owner.typ.callConv = ccClosure
|
||||
#echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
|
||||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||
@@ -301,15 +358,17 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
|
||||
var s = n.sym
|
||||
if interestingVar(s) and i.fn.id != s.owner.id:
|
||||
captureVar(o, i, s, n.info)
|
||||
elif isInnerProc(s, o.fn) and tfCapturesEnv in s.typ.flags and s != i.fn:
|
||||
elif s.kind in {skProc, skMethod, skConverter} and
|
||||
s.skipGenericOwner == o.fn and
|
||||
tfCapturesEnv in s.typ.flags and s != i.fn:
|
||||
# call to some other inner proc; we need to track the dependencies for
|
||||
# this:
|
||||
let env = PEnv(IdTableGet(o.lambdasToEnv, i.fn))
|
||||
if env == nil: InternalError(n.info, "no environment computed")
|
||||
let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
|
||||
if env == nil: internalError(n.info, "no environment computed")
|
||||
if o.currentEnv != env:
|
||||
discard addDep(o.currentEnv, env, i.fn)
|
||||
InternalError(n.info, "too complex environment handling required")
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
|
||||
internalError(n.info, "too complex environment handling required")
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure: discard
|
||||
else:
|
||||
for k in countup(0, sonsLen(n) - 1):
|
||||
gatherVars(o, i, n.sons[k])
|
||||
@@ -346,7 +405,7 @@ proc makeClosure(prc, env: PSym, info: TLineInfo): PNode =
|
||||
|
||||
proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
|
||||
of nkSym:
|
||||
let s = n.sym
|
||||
if s == i.fn:
|
||||
@@ -360,13 +419,14 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
|
||||
result = makeClosure(s, i.closureParam, n.info)
|
||||
else:
|
||||
# captured symbol?
|
||||
result = IdNodeTableGet(i.localsToAccess, n.sym)
|
||||
of nkLambdaKinds:
|
||||
result = transformInnerProc(o, i, n.sons[namePos])
|
||||
result = idNodeTableGet(i.localsToAccess, n.sym)
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil:
|
||||
result = transformInnerProc(o, i, n.sons[namePos])
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef:
|
||||
nkClosure:
|
||||
# don't recurse here:
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
for j in countup(0, sonsLen(n) - 1):
|
||||
let x = transformInnerProc(o, i, n.sons[j])
|
||||
@@ -381,7 +441,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
nil
|
||||
discard
|
||||
of nkSym:
|
||||
if isInnerProc(n.sym, o.fn) and not containsOrIncl(o.processed, n.sym.id):
|
||||
var inner = newInnerContext(n.sym)
|
||||
@@ -395,8 +455,9 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
|
||||
if inner.closureParam != nil:
|
||||
let ti = transformInnerProc(o, inner, body)
|
||||
if ti != nil: n.sym.ast.sons[bodyPos] = ti
|
||||
of nkLambdaKinds:
|
||||
searchForInnerProcs(o, n.sons[namePos])
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil:
|
||||
searchForInnerProcs(o, n.sons[namePos])
|
||||
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
|
||||
# some nodes open a new scope, so they are candidates for the insertion
|
||||
# of closure creation; however for simplicity we merge closures between
|
||||
@@ -417,26 +478,26 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
|
||||
# counts, not the block where it is captured!
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkCommentStmt: nil
|
||||
if it.kind == nkCommentStmt: discard
|
||||
elif it.kind == nkIdentDefs:
|
||||
var L = sonsLen(it)
|
||||
if it.sons[0].kind != nkSym: InternalError(it.info, "transformOuter")
|
||||
if it.sons[0].kind != nkSym: internalError(it.info, "transformOuter")
|
||||
#echo "set: ", it.sons[0].sym.name.s, " ", o.currentBlock == nil
|
||||
IdTablePut(o.localsToEnv, it.sons[0].sym, o.currentEnv)
|
||||
idTablePut(o.localsToEnv, it.sons[0].sym, o.currentEnv)
|
||||
searchForInnerProcs(o, it.sons[L-1])
|
||||
elif it.kind == nkVarTuple:
|
||||
var L = sonsLen(it)
|
||||
for j in countup(0, L-3):
|
||||
#echo "set: ", it.sons[j].sym.name.s, " ", o.currentBlock == nil
|
||||
IdTablePut(o.localsToEnv, it.sons[j].sym, o.currentEnv)
|
||||
idTablePut(o.localsToEnv, it.sons[j].sym, o.currentEnv)
|
||||
searchForInnerProcs(o, it.sons[L-1])
|
||||
else:
|
||||
InternalError(it.info, "transformOuter")
|
||||
internalError(it.info, "transformOuter")
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef:
|
||||
nkClosure, nkTypeSection:
|
||||
# don't recurse here:
|
||||
# XXX recurse here and setup 'up' pointers
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
searchForInnerProcs(o, n.sons[i])
|
||||
@@ -451,26 +512,20 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
result.sons[0] = le
|
||||
result.sons[1] = ri
|
||||
|
||||
proc addVar*(father, v: PNode) =
|
||||
var vpart = newNodeI(nkIdentDefs, v.info)
|
||||
addSon(vpart, v)
|
||||
addSon(vpart, ast.emptyNode)
|
||||
addSon(vpart, ast.emptyNode)
|
||||
addSon(father, vpart)
|
||||
proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
|
||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||
incl(result.flags, sfShadowed)
|
||||
result.typ = newType(tyRef, o.fn)
|
||||
result.typ.rawAddSon(e.obj)
|
||||
|
||||
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
|
||||
if e.closure == nil:
|
||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||
incl(result.flags, sfShadowed)
|
||||
result.typ = newType(tyRef, o.fn)
|
||||
result.typ.rawAddSon(e.tup)
|
||||
e.closure = result
|
||||
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
|
||||
if e.createdVar == nil:
|
||||
result = newClosureCreationVar(o, e)
|
||||
e.createdVar = result
|
||||
else:
|
||||
result = e.closure
|
||||
|
||||
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||
var env = getClosureVar(o, scope)
|
||||
result = e.createdVar
|
||||
|
||||
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
|
||||
result = newNodeI(nkStmtList, env.info)
|
||||
var v = newNodeI(nkVarSection, env.info)
|
||||
addVar(v, newSymNode(env))
|
||||
@@ -485,23 +540,130 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||
# maybe later: (sfByCopy in local.flags)
|
||||
# add ``env.param = param``
|
||||
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
|
||||
IdNodeTablePut(o.localsToAccess, local, fieldAccess)
|
||||
# it can happen that we already captured 'local' in some other environment
|
||||
# then we capture by copy for now. This is not entirely correct but better
|
||||
# than nothing:
|
||||
let existing = idNodeTableGet(o.localsToAccess, local)
|
||||
if existing.isNil:
|
||||
idNodeTablePut(o.localsToAccess, local, fieldAccess)
|
||||
else:
|
||||
result.add(newAsgnStmt(fieldAccess, existing, env.info))
|
||||
# add support for 'up' references:
|
||||
for e, field in items(scope.deps):
|
||||
# add ``env.up = env2``
|
||||
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
|
||||
newSymNode(getClosureVar(o, e)), env.info))
|
||||
|
||||
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||
var env = getClosureVar(o, scope)
|
||||
result = rawClosureCreation(o, scope, env)
|
||||
|
||||
proc generateIterClosureCreation(o: POuterContext; env: PEnv;
|
||||
scope: PNode): PSym =
|
||||
if env.createdVarComesFromIter or env.createdVar.isNil:
|
||||
# we have to create a new closure:
|
||||
result = newClosureCreationVar(o, env)
|
||||
let cc = rawClosureCreation(o, env, result)
|
||||
var insertPoint = scope.sons[0]
|
||||
if insertPoint.kind == nkEmpty: scope.sons[0] = cc
|
||||
else:
|
||||
assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
|
||||
for x in cc: insertPoint.add(x)
|
||||
if env.createdVar == nil: env.createdVar = result
|
||||
else:
|
||||
result = env.createdVar
|
||||
env.createdVarComesFromIter = true
|
||||
|
||||
proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
||||
|
||||
proc transformOuterProc(o: POuterContext, n: PNode): PNode
|
||||
|
||||
proc transformYield(c: POuterContext, n: PNode): PNode =
|
||||
inc c.state.typ.n.sons[1].intVal
|
||||
let stateNo = c.state.typ.n.sons[1].intVal
|
||||
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
|
||||
var retStmt = newNodeI(nkReturnStmt, n.info)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
var a = newNodeI(nkAsgn, n.sons[0].info)
|
||||
var retVal = transformOuterProc(c, n.sons[0])
|
||||
addSon(a, newSymNode(c.resultSym))
|
||||
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
|
||||
retStmt.add(a)
|
||||
else:
|
||||
retStmt.add(emptyNode)
|
||||
|
||||
var stateLabelStmt = newNodeI(nkState, n.info)
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(retStmt)
|
||||
result.add(stateLabelStmt)
|
||||
|
||||
proc transformReturn(c: POuterContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(n)
|
||||
|
||||
proc outerProcSons(o: POuterContext, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let x = transformOuterProc(o, n.sons[i])
|
||||
if x != nil: n.sons[i] = x
|
||||
|
||||
proc liftIterSym*(n: PNode): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
let iter = n.sym
|
||||
assert iter.kind == skClosureIterator
|
||||
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
var env = copySym(getHiddenParam(iter))
|
||||
env.kind = skLet
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
addVar(v, newSymNode(env))
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env))
|
||||
result.add makeClosure(iter, env, n.info)
|
||||
|
||||
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||
if n == nil: return nil
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
|
||||
of nkSym:
|
||||
var local = n.sym
|
||||
var closure = PEnv(IdTableGet(o.lambdasToEnv, local))
|
||||
|
||||
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
|
||||
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
|
||||
return indirectAccess(newSymNode(o.closureParam), local, n.info)
|
||||
|
||||
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
||||
|
||||
if local.kind == skClosureIterator:
|
||||
# consider: [i1, i2, i1] Since we merged the iterator's closure
|
||||
# with the captured owning variables, we need to generate the
|
||||
# closure generation code again:
|
||||
if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
|
||||
# XXX why doesn't this work?
|
||||
if closure.isNil:
|
||||
return liftIterSym(n)
|
||||
else:
|
||||
let createdVar = generateIterClosureCreation(o, closure,
|
||||
closure.attachedNode)
|
||||
return makeClosure(local, createdVar, n.info)
|
||||
|
||||
if closure != nil:
|
||||
# we need to replace the lambda with '(lambda, env)':
|
||||
let a = closure.closure
|
||||
# we need to replace the lambda with '(lambda, env)':
|
||||
|
||||
let a = closure.createdVar
|
||||
if a != nil:
|
||||
return makeClosure(local, a, n.info)
|
||||
else:
|
||||
@@ -511,12 +673,12 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||
if scope.sons[0].kind == nkEmpty:
|
||||
# change the empty node to contain the closure construction:
|
||||
scope.sons[0] = generateClosureCreation(o, closure)
|
||||
let x = closure.closure
|
||||
let x = closure.createdVar
|
||||
assert x != nil
|
||||
return makeClosure(local, x, n.info)
|
||||
|
||||
if not contains(o.capturedVars, local.id): return
|
||||
var env = PEnv(IdTableGet(o.localsToEnv, local))
|
||||
var env = PEnv(idTableGet(o.localsToEnv, local))
|
||||
if env == nil: return
|
||||
var scope = env.attachedNode
|
||||
assert scope.kind == nkStmtList
|
||||
@@ -526,26 +688,55 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||
|
||||
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
|
||||
# if sfByCopy notin local.flags:
|
||||
result = IdNodeTableGet(o.localsToAccess, local)
|
||||
result = idNodeTableGet(o.localsToAccess, local)
|
||||
assert result != nil, "cannot find: " & local.name.s
|
||||
# else it is captured by copy and this means that 'outer' should continue
|
||||
# to access the local as a local.
|
||||
of nkLambdaKinds:
|
||||
result = transformOuterProc(o, n.sons[namePos])
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef:
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil:
|
||||
result = transformOuterProc(o, n.sons[namePos])
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkClosure:
|
||||
# don't recurse here:
|
||||
nil
|
||||
discard
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
let x = transformOuterProc(o, n.sons[1])
|
||||
if x != nil: n.sons[1] = x
|
||||
result = transformOuterConv(n)
|
||||
of nkYieldStmt:
|
||||
if o.isIter: result = transformYield(o, n)
|
||||
else: outerProcSons(o, n)
|
||||
of nkReturnStmt:
|
||||
if o.isIter: result = transformReturn(o, n)
|
||||
else: outerProcSons(o, n)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let x = transformOuterProc(o, n.sons[i])
|
||||
if x != nil: n.sons[i] = x
|
||||
outerProcSons(o, n)
|
||||
|
||||
proc liftIterator(c: POuterContext, body: PNode): PNode =
|
||||
let iter = c.fn
|
||||
result = newNodeI(nkStmtList, iter.info)
|
||||
var gs = newNodeI(nkGotoState, iter.info)
|
||||
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
|
||||
result.add(gs)
|
||||
var state0 = newNodeI(nkState, iter.info)
|
||||
state0.add(newIntNode(nkIntLit, 0))
|
||||
result.add(state0)
|
||||
|
||||
let newBody = transformOuterProc(c, body)
|
||||
if newBody != nil:
|
||||
result.add(newBody)
|
||||
else:
|
||||
result.add(body)
|
||||
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
|
||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
|
||||
c.state,iter.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
|
||||
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
@@ -557,16 +748,19 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||
let params = fn.typ.n
|
||||
for i in 1.. <params.len:
|
||||
if params.sons[i].kind != nkSym:
|
||||
InternalError(params.info, "liftLambdas: strange params")
|
||||
internalError(params.info, "liftLambdas: strange params")
|
||||
let param = params.sons[i].sym
|
||||
IdTablePut(o.localsToEnv, param, o.currentEnv)
|
||||
idTablePut(o.localsToEnv, param, o.currentEnv)
|
||||
# put the 'result' into the environment so it can be captured:
|
||||
let ast = fn.ast
|
||||
if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
|
||||
IdTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
|
||||
idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
|
||||
searchForInnerProcs(o, body)
|
||||
discard transformOuterProc(o, body)
|
||||
result = ex
|
||||
if o.isIter:
|
||||
result = liftIterator(o, ex)
|
||||
else:
|
||||
discard transformOuterProc(o, body)
|
||||
result = ex
|
||||
|
||||
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
|
||||
@@ -581,147 +775,6 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||
|
||||
# ------------------- iterator transformation --------------------------------
|
||||
|
||||
discard """
|
||||
iterator chain[S, T](a, b: *S->T, args: *S): T =
|
||||
for x in a(args): yield x
|
||||
for x in b(args): yield x
|
||||
|
||||
let c = chain(f, g)
|
||||
for x in c: echo x
|
||||
|
||||
# translated to:
|
||||
let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain))
|
||||
"""
|
||||
|
||||
type
|
||||
TIterContext {.final, pure.} = object
|
||||
iter, closureParam, state, resultSym: PSym
|
||||
capturedVars: TIntSet
|
||||
tup: PType
|
||||
|
||||
proc newIterResult(iter: PSym): PSym =
|
||||
result = iter.ast.sons[resultPos].sym
|
||||
when false:
|
||||
result = newSym(skResult, getIdent":result", iter, iter.info)
|
||||
result.typ = iter.typ.sons[0]
|
||||
incl(result.flags, sfUsed)
|
||||
|
||||
proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
||||
|
||||
proc transfIterBody(c: var TIterContext, n: PNode): PNode =
|
||||
# gather used vars for closure generation
|
||||
if n == nil: return nil
|
||||
case n.kind
|
||||
of nkSym:
|
||||
var s = n.sym
|
||||
if interestingIterVar(s) and c.iter.id == s.owner.id:
|
||||
if not containsOrIncl(c.capturedVars, s.id): addField(c.tup, s)
|
||||
result = indirectAccess(newSymNode(c.closureParam), s, n.info)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
|
||||
of nkYieldStmt:
|
||||
inc c.state.typ.n.sons[1].intVal
|
||||
let stateNo = c.state.typ.n.sons[1].intVal
|
||||
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
|
||||
var retStmt = newNodeI(nkReturnStmt, n.info)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
var a = newNodeI(nkAsgn, n.sons[0].info)
|
||||
var retVal = transfIterBody(c, n.sons[0])
|
||||
addSon(a, newSymNode(c.resultSym))
|
||||
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
|
||||
retStmt.add(a)
|
||||
else:
|
||||
retStmt.add(emptyNode)
|
||||
|
||||
var stateLabelStmt = newNodeI(nkState, n.info)
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(retStmt)
|
||||
result.add(stateLabelStmt)
|
||||
of nkReturnStmt:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(n)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
let x = transfIterBody(c, n.sons[i])
|
||||
if x != nil: n.sons[i] = x
|
||||
|
||||
proc getStateType(iter: PSym): PType =
|
||||
var n = newNodeI(nkRange, iter.info)
|
||||
addSon(n, newIntNode(nkIntLit, -1))
|
||||
addSon(n, newIntNode(nkIntLit, 0))
|
||||
result = newType(tyRange, iter)
|
||||
result.n = n
|
||||
rawAddSon(result, getSysType(tyInt))
|
||||
|
||||
proc liftIterator*(iter: PSym, body: PNode): PNode =
|
||||
var c: TIterContext
|
||||
c.iter = iter
|
||||
c.capturedVars = initIntSet()
|
||||
|
||||
c.tup = newType(tyTuple, iter)
|
||||
c.tup.n = newNodeI(nkRecList, iter.info)
|
||||
|
||||
var cp = newSym(skParam, getIdent(paramname), iter, iter.info)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = newType(tyRef, iter)
|
||||
rawAddSon(cp.typ, c.tup)
|
||||
c.closureParam = cp
|
||||
addHiddenParam(iter, cp)
|
||||
|
||||
c.state = newSym(skField, getIdent(":state"), iter, iter.info)
|
||||
c.state.typ = getStateType(iter)
|
||||
addField(c.tup, c.state)
|
||||
|
||||
if iter.typ.sons[0] != nil:
|
||||
c.resultSym = newIterResult(iter)
|
||||
iter.ast.add(newSymNode(c.resultSym))
|
||||
|
||||
result = newNodeI(nkStmtList, iter.info)
|
||||
var gs = newNodeI(nkGotoState, iter.info)
|
||||
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
|
||||
result.add(gs)
|
||||
var state0 = newNodeI(nkState, iter.info)
|
||||
state0.add(newIntNode(nkIntLit, 0))
|
||||
result.add(state0)
|
||||
|
||||
let newBody = transfIterBody(c, body)
|
||||
if newBody != nil:
|
||||
result.add(newBody)
|
||||
else:
|
||||
result.add(body)
|
||||
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
|
||||
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
|
||||
c.state,iter.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
|
||||
proc liftIterSym*(n: PNode): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let iter = n.sym
|
||||
assert iter.kind == skIterator
|
||||
var env = copySym(getHiddenParam(iter))
|
||||
env.kind = skLet
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
addVar(v, newSymNode(env))
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env))
|
||||
result.add makeClosure(iter, env, n.info)
|
||||
|
||||
proc liftForLoop*(body: PNode): PNode =
|
||||
# problem ahead: the iterator could be invoked indirectly, but then
|
||||
# we don't know what environment to create here:
|
||||
@@ -751,17 +804,17 @@ proc liftForLoop*(body: PNode): PNode =
|
||||
...
|
||||
"""
|
||||
var L = body.len
|
||||
InternalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
|
||||
internalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
|
||||
var call = body[L-2]
|
||||
|
||||
result = newNodeI(nkStmtList, body.info)
|
||||
|
||||
# static binding?
|
||||
var env: PSym
|
||||
if call[0].kind == nkSym and call[0].sym.kind == skIterator:
|
||||
# createClose()
|
||||
if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
|
||||
# createClosure()
|
||||
let iter = call[0].sym
|
||||
assert iter.kind == skIterator
|
||||
assert iter.kind == skClosureIterator
|
||||
env = copySym(getHiddenParam(iter))
|
||||
|
||||
var v = newNodeI(nkVarSection, body.info)
|
||||
@@ -786,7 +839,7 @@ proc liftForLoop*(body: PNode): PNode =
|
||||
addSon(vpart, body[i])
|
||||
|
||||
addSon(vpart, ast.emptyNode) # no explicit type
|
||||
if not env.isnil:
|
||||
if not env.isNil:
|
||||
call.sons[0] = makeClosure(call.sons[0].sym, env, body.info)
|
||||
addSon(vpart, call)
|
||||
addSon(v2, vpart)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -43,9 +43,10 @@ type
|
||||
tkLambda, tkLet,
|
||||
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
|
||||
tkObject, tkOf, tkOr, tkOut,
|
||||
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
|
||||
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
|
||||
tkTemplate,
|
||||
tkTry, tkTuple, tkType, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
|
||||
tkTry, tkTuple, tkType, tkUsing,
|
||||
tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
|
||||
tkYield, # end of keywords
|
||||
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
|
||||
tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
|
||||
@@ -78,9 +79,10 @@ const
|
||||
"macro", "method", "mixin", "mod",
|
||||
"nil", "not", "notin", "object", "of", "or",
|
||||
"out", "proc", "ptr", "raise", "ref", "return",
|
||||
"shared", "shl", "shr", "static",
|
||||
"shl", "shr", "static",
|
||||
"template",
|
||||
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor",
|
||||
"try", "tuple", "type", "using",
|
||||
"var", "when", "while", "with", "without", "xor",
|
||||
"yield",
|
||||
"tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
|
||||
"tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
|
||||
@@ -99,6 +101,7 @@ type
|
||||
base10, # base10 is listed as the first element,
|
||||
# so that it is the correct default value
|
||||
base2, base8, base16
|
||||
|
||||
TToken* = object # a Nimrod token
|
||||
tokType*: TTokType # the type of the token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
@@ -108,15 +111,20 @@ type
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: TNumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
strongSpaceA*: int8 # leading spaces of an operator
|
||||
strongSpaceB*: int8 # trailing spaces of an operator
|
||||
literal*: string # the parsed (string) literal; and
|
||||
# documentation comments are here too
|
||||
line*, col*: int
|
||||
|
||||
TLexer* = object of TBaseLexer
|
||||
fileIdx*: int32
|
||||
indentAhead*: int # if > 0 an indendation has already been read
|
||||
# this is needed because scanning comments
|
||||
# needs so much look-ahead
|
||||
|
||||
currLineIndent*: int
|
||||
strongSpaces*: bool
|
||||
|
||||
|
||||
var gLinesCompiled*: int # all lines that have been compiled
|
||||
|
||||
@@ -124,14 +132,16 @@ proc isKeyword*(kind: TTokType): bool
|
||||
proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
|
||||
proc rawGetTok*(L: var TLexer, tok: var TToken)
|
||||
# reads in the next token into tok and skips it
|
||||
proc getColumn*(L: TLexer): int
|
||||
proc getLineInfo*(L: TLexer): TLineInfo
|
||||
|
||||
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
|
||||
newLineInfo(L.fileIdx, tok.line, tok.col)
|
||||
|
||||
proc closeLexer*(lex: var TLexer)
|
||||
proc PrintTok*(tok: TToken)
|
||||
proc printTok*(tok: TToken)
|
||||
proc tokToStr*(tok: TToken): string
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||
OpenLexer(lex, filename.fileInfoIdx, inputStream)
|
||||
openLexer(lex, filename.fileInfoIdx, inputstream)
|
||||
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
|
||||
|
||||
@@ -155,19 +165,20 @@ proc tokToStr*(tok: TToken): string =
|
||||
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
|
||||
of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
|
||||
of tkParLe..tkColon, tkEof, tkAccent:
|
||||
result = tokTypeToStr[tok.tokType]
|
||||
result = TokTypeToStr[tok.tokType]
|
||||
else:
|
||||
if tok.ident != nil:
|
||||
result = tok.ident.s
|
||||
else:
|
||||
InternalError("tokToStr")
|
||||
internalError("tokToStr")
|
||||
result = ""
|
||||
|
||||
proc prettyTok*(tok: TToken): string =
|
||||
if IsKeyword(tok.tokType): result = "keyword " & tok.ident.s
|
||||
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
|
||||
else: result = tokToStr(tok)
|
||||
|
||||
proc PrintTok*(tok: TToken) =
|
||||
proc printTok*(tok: TToken) =
|
||||
write(stdout, tok.line, ":", tok.col, "\t")
|
||||
write(stdout, TokTypeToStr[tok.tokType])
|
||||
write(stdout, " ")
|
||||
writeln(stdout, tokToStr(tok))
|
||||
@@ -175,18 +186,20 @@ proc PrintTok*(tok: TToken) =
|
||||
var dummyIdent: PIdent
|
||||
|
||||
proc initToken*(L: var TToken) =
|
||||
L.TokType = tkInvalid
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.Indent = 0
|
||||
L.indent = 0
|
||||
L.strongSpaceA = 0
|
||||
L.literal = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
L.ident = dummyIdent
|
||||
|
||||
proc fillToken(L: var TToken) =
|
||||
L.TokType = tkInvalid
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.Indent = 0
|
||||
L.indent = 0
|
||||
L.strongSpaceA = 0
|
||||
setLen(L.literal, 0)
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -194,26 +207,27 @@ proc fillToken(L: var TToken) =
|
||||
|
||||
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.fileIdx = fileIdx
|
||||
lex.fileIdx = fileidx
|
||||
lex.indentAhead = - 1
|
||||
inc(lex.Linenumber, inputstream.lineOffset)
|
||||
lex.currLineIndent = 0
|
||||
inc(lex.lineNumber, inputstream.lineOffset)
|
||||
|
||||
proc closeLexer(lex: var TLexer) =
|
||||
inc(gLinesCompiled, lex.LineNumber)
|
||||
inc(gLinesCompiled, lex.lineNumber)
|
||||
closeBaseLexer(lex)
|
||||
|
||||
proc getColumn(L: TLexer): int =
|
||||
result = getColNumber(L, L.bufPos)
|
||||
result = getColNumber(L, L.bufpos)
|
||||
|
||||
proc getLineInfo(L: TLexer): TLineInfo =
|
||||
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
|
||||
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
|
||||
|
||||
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
msgs.Message(getLineInfo(L), msg, arg)
|
||||
msgs.message(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
|
||||
msgs.Message(info, msg, arg)
|
||||
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
|
||||
msgs.message(info, msg, arg)
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
@@ -221,7 +235,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.literal, buf[pos])
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
@@ -229,46 +243,47 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
add(tok.literal, '_')
|
||||
Inc(pos)
|
||||
L.bufPos = pos
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc matchTwoChars(L: TLexer, first: Char, second: TCharSet): bool =
|
||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in Second)
|
||||
proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool =
|
||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
for i in countup(0, len(s) + 0 - 1):
|
||||
if s[i] in {'.', 'e', 'E'}:
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
for i in countup(0, len(s) - 1):
|
||||
if s[i] in {'.', 'e', 'E'}:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc GetNumber(L: var TLexer): TToken =
|
||||
proc getNumber(L: var TLexer): TToken =
|
||||
var
|
||||
pos, endpos: int
|
||||
xi: biggestInt
|
||||
xi: BiggestInt
|
||||
# get the base:
|
||||
result.tokType = tkIntLit # int literal until we know better
|
||||
result.literal = ""
|
||||
result.base = base10 # BUGFIX
|
||||
pos = L.bufpos # make sure the literal is correct for error messages:
|
||||
var eallowed = false
|
||||
if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}:
|
||||
matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'})
|
||||
else:
|
||||
matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
|
||||
eallowed = true
|
||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||
add(result.literal, '.')
|
||||
inc(L.bufpos)
|
||||
#matchUnderscoreChars(L, result, ['A'..'Z', 'a'..'z', '0'..'9'])
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
if L.buf[L.bufpos] in {'e', 'E'}:
|
||||
add(result.literal, 'e')
|
||||
eallowed = true
|
||||
if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
|
||||
add(result.literal, 'e')
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
add(result.literal, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
add(result.literal, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
endpos = L.bufpos
|
||||
if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}:
|
||||
#matchUnderscoreChars(L, result, ['''', 'f', 'F', 'i', 'I', '0'..'9']);
|
||||
if L.buf[endpos] == '\'': inc(endpos)
|
||||
L.bufpos = pos # restore position
|
||||
case L.buf[endpos]
|
||||
@@ -384,32 +399,32 @@ proc GetNumber(L: var TLexer): TToken =
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
||||
inc(pos)
|
||||
else: break
|
||||
else: InternalError(getLineInfo(L), "getNumber")
|
||||
else: internalError(getLineInfo(L), "getNumber")
|
||||
case result.tokType
|
||||
of tkIntLit, tkInt64Lit: result.iNumber = xi
|
||||
of tkInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
|
||||
of tkInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
|
||||
of tkInt32Lit: result.iNumber = biggestInt(toU32(xi))
|
||||
of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
|
||||
of tkInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
|
||||
of tkInt32Lit: result.iNumber = BiggestInt(toU32(xi))
|
||||
of tkUIntLit, tkUInt64Lit: result.iNumber = xi
|
||||
of tkUInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
|
||||
of tkUInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
|
||||
of tkUInt32Lit: result.iNumber = biggestInt(toU32(xi))
|
||||
of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
|
||||
of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
|
||||
of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
|
||||
of tkFloat32Lit:
|
||||
result.fNumber = (cast[PFloat32](addr(xi)))[]
|
||||
# note: this code is endian neutral!
|
||||
# XXX: Test this on big endian machine!
|
||||
of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
|
||||
else: InternalError(getLineInfo(L), "getNumber")
|
||||
else: internalError(getLineInfo(L), "getNumber")
|
||||
elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
|
||||
(result.tokType == tkFloat64Lit):
|
||||
result.fnumber = parseFloat(result.literal)
|
||||
result.fNumber = parseFloat(result.literal)
|
||||
if result.tokType == tkIntLit: result.tokType = tkFloatLit
|
||||
else:
|
||||
result.iNumber = ParseBiggestInt(result.literal)
|
||||
if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
|
||||
if result.tokType == tkIntLit:
|
||||
else:
|
||||
result.iNumber = parseBiggestInt(result.literal)
|
||||
if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
|
||||
if result.tokType == tkIntLit:
|
||||
result.tokType = tkInt64Lit
|
||||
elif result.tokType != tkInt64Lit:
|
||||
elif result.tokType in {tkInt8Lit, tkInt16Lit}:
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
except EInvalidValue:
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
@@ -428,7 +443,7 @@ proc handleHexChar(L: var TLexer, xi: var int) =
|
||||
of 'A'..'F':
|
||||
xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
|
||||
inc(L.bufpos)
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc handleDecChars(L: var TLexer, xi: var int) =
|
||||
while L.buf[L.bufpos] in {'0'..'9'}:
|
||||
@@ -439,51 +454,51 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos) # skip '\'
|
||||
case L.buf[L.bufpos]
|
||||
of 'n', 'N':
|
||||
if tok.toktype == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
|
||||
if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
|
||||
add(tok.literal, tnl)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'r', 'R', 'c', 'C':
|
||||
add(tok.literal, CR)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'l', 'L':
|
||||
add(tok.literal, LF)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'f', 'F':
|
||||
add(tok.literal, FF)
|
||||
inc(L.bufpos)
|
||||
of 'e', 'E':
|
||||
add(tok.literal, ESC)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'a', 'A':
|
||||
add(tok.literal, BEL)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'b', 'B':
|
||||
add(tok.literal, BACKSPACE)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'v', 'V':
|
||||
add(tok.literal, VT)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 't', 'T':
|
||||
add(tok.literal, Tabulator)
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '\'', '\"':
|
||||
add(tok.literal, L.buf[L.bufpos])
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '\\':
|
||||
add(tok.literal, '\\')
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of 'x', 'X':
|
||||
inc(L.bufpos)
|
||||
var xi = 0
|
||||
handleHexChar(L, xi)
|
||||
handleHexChar(L, xi)
|
||||
add(tok.literal, Chr(xi))
|
||||
add(tok.literal, chr(xi))
|
||||
of '0'..'9':
|
||||
if matchTwoChars(L, '0', {'0'..'9'}):
|
||||
lexMessage(L, warnOctalEscape)
|
||||
var xi = 0
|
||||
handleDecChars(L, xi)
|
||||
if (xi <= 255): add(tok.literal, Chr(xi))
|
||||
if (xi <= 255): add(tok.literal, chr(xi))
|
||||
else: lexMessage(L, errInvalidCharacterConstant)
|
||||
else: lexMessage(L, errInvalidCharacterConstant)
|
||||
|
||||
@@ -493,7 +508,7 @@ proc newString(s: cstring, len: int): string =
|
||||
for i in 0 .. <len:
|
||||
result[i] = s[i]
|
||||
|
||||
proc HandleCRLF(L: var TLexer, pos: int): int =
|
||||
proc handleCRLF(L: var TLexer, pos: int): int =
|
||||
template registerLine =
|
||||
let col = L.getColNumber(pos)
|
||||
|
||||
@@ -508,21 +523,21 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
|
||||
case L.buf[pos]
|
||||
of CR:
|
||||
registerLine()
|
||||
result = nimlexbase.HandleCR(L, pos)
|
||||
result = nimlexbase.handleCR(L, pos)
|
||||
of LF:
|
||||
registerLine()
|
||||
result = nimlexbase.HandleLF(L, pos)
|
||||
result = nimlexbase.handleLF(L, pos)
|
||||
else: result = pos
|
||||
|
||||
proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
||||
var pos = L.bufPos + 1 # skip "
|
||||
var pos = L.bufpos + 1 # skip "
|
||||
var buf = L.buf # put `buf` in a register
|
||||
var line = L.linenumber # save linenumber for better error message
|
||||
var line = L.lineNumber # save linenumber for better error message
|
||||
if buf[pos] == '\"' and buf[pos+1] == '\"':
|
||||
tok.tokType = tkTripleStrLit # long string literal:
|
||||
inc(pos, 2) # skip ""
|
||||
# skip leading newline:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
while true:
|
||||
case buf[pos]
|
||||
@@ -532,20 +547,20 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
||||
L.bufpos = pos + 3 # skip the three """
|
||||
break
|
||||
add(tok.literal, '\"')
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.literal, tnl)
|
||||
of nimlexbase.EndOfFile:
|
||||
var line2 = L.linenumber
|
||||
L.LineNumber = line
|
||||
var line2 = L.lineNumber
|
||||
L.lineNumber = line
|
||||
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
|
||||
L.LineNumber = line2
|
||||
L.lineNumber = line2
|
||||
break
|
||||
else:
|
||||
add(tok.literal, buf[pos])
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
else:
|
||||
# ordinary string literal
|
||||
if rawMode: tok.tokType = tkRStrLit
|
||||
@@ -563,23 +578,23 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
||||
lexMessage(L, errClosingQuoteExpected)
|
||||
break
|
||||
elif (c == '\\') and not rawMode:
|
||||
L.bufPos = pos
|
||||
L.bufpos = pos
|
||||
getEscapedChar(L, tok)
|
||||
pos = L.bufPos
|
||||
pos = L.bufpos
|
||||
else:
|
||||
add(tok.literal, c)
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc getCharacter(L: var TLexer, tok: var TToken) =
|
||||
Inc(L.bufpos) # skip '
|
||||
inc(L.bufpos) # skip '
|
||||
var c = L.buf[L.bufpos]
|
||||
case c
|
||||
of '\0'..Pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
|
||||
of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
|
||||
of '\\': getEscapedChar(L, tok)
|
||||
else:
|
||||
tok.literal = $c
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
|
||||
inc(L.bufpos) # skip '
|
||||
|
||||
@@ -600,7 +615,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
else: break
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
h = !$h
|
||||
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
L.bufpos = pos
|
||||
@@ -625,9 +640,17 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
if c notin OpChars: break
|
||||
h = h !& Ord(c)
|
||||
Inc(pos)
|
||||
h = h !& ord(c)
|
||||
inc(pos)
|
||||
endOperator(L, tok, pos, h)
|
||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||
# be an operator too) gets the preceeding spaces:
|
||||
tok.strongSpaceB = 0
|
||||
while buf[pos] == ' ':
|
||||
inc pos
|
||||
inc tok.strongSpaceB
|
||||
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||
tok.strongSpaceB = -1
|
||||
|
||||
proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
@@ -671,22 +694,26 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
proc skip(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tok.strongSpaceA = 0
|
||||
while true:
|
||||
case buf[pos]
|
||||
of ' ':
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
inc(tok.strongSpaceA)
|
||||
of Tabulator:
|
||||
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
||||
inc(pos)
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
var indent = 0
|
||||
while buf[pos] == ' ':
|
||||
Inc(pos)
|
||||
Inc(indent)
|
||||
inc(pos)
|
||||
inc(indent)
|
||||
tok.strongSpaceA = 0
|
||||
if buf[pos] > ' ':
|
||||
tok.indent = indent
|
||||
L.currLineIndent = indent
|
||||
break
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
@@ -696,11 +723,14 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
fillToken(tok)
|
||||
if L.indentAhead >= 0:
|
||||
tok.indent = L.indentAhead
|
||||
L.currLineIndent = L.indentAhead
|
||||
L.indentAhead = -1
|
||||
else:
|
||||
tok.indent = -1
|
||||
skip(L, tok)
|
||||
var c = L.buf[L.bufpos]
|
||||
tok.line = L.lineNumber
|
||||
tok.col = getColNumber(L, L.bufpos)
|
||||
if c in SymStartChars - {'r', 'R', 'l'}:
|
||||
getSymbol(L, tok)
|
||||
else:
|
||||
@@ -716,8 +746,8 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
else:
|
||||
getOperator(L, tok)
|
||||
of ',':
|
||||
tok.toktype = tkComma
|
||||
Inc(L.bufpos)
|
||||
tok.tokType = tkComma
|
||||
inc(L.bufpos)
|
||||
of 'l':
|
||||
# if we parsed exactly one character and its a small L (l), this
|
||||
# is treated as a warning because it may be confused with the number 1
|
||||
@@ -725,59 +755,59 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
lexMessage(L, warnSmallLshouldNotBeUsed)
|
||||
getSymbol(L, tok)
|
||||
of 'r', 'R':
|
||||
if L.buf[L.bufPos + 1] == '\"':
|
||||
Inc(L.bufPos)
|
||||
if L.buf[L.bufpos + 1] == '\"':
|
||||
inc(L.bufpos)
|
||||
getString(L, tok, true)
|
||||
else:
|
||||
getSymbol(L, tok)
|
||||
of '(':
|
||||
Inc(L.bufpos)
|
||||
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
|
||||
tok.toktype = tkParDotLe
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
|
||||
tok.tokType = tkParDotLe
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.toktype = tkParLe
|
||||
tok.tokType = tkParLe
|
||||
of ')':
|
||||
tok.toktype = tkParRi
|
||||
Inc(L.bufpos)
|
||||
tok.tokType = tkParRi
|
||||
inc(L.bufpos)
|
||||
of '[':
|
||||
Inc(L.bufpos)
|
||||
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
|
||||
tok.toktype = tkBracketDotLe
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
|
||||
tok.tokType = tkBracketDotLe
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.toktype = tkBracketLe
|
||||
tok.tokType = tkBracketLe
|
||||
of ']':
|
||||
tok.toktype = tkBracketRi
|
||||
Inc(L.bufpos)
|
||||
tok.tokType = tkBracketRi
|
||||
inc(L.bufpos)
|
||||
of '.':
|
||||
if L.buf[L.bufPos+1] == ']':
|
||||
if L.buf[L.bufpos+1] == ']':
|
||||
tok.tokType = tkBracketDotRi
|
||||
Inc(L.bufpos, 2)
|
||||
elif L.buf[L.bufPos+1] == '}':
|
||||
inc(L.bufpos, 2)
|
||||
elif L.buf[L.bufpos+1] == '}':
|
||||
tok.tokType = tkCurlyDotRi
|
||||
Inc(L.bufpos, 2)
|
||||
elif L.buf[L.bufPos+1] == ')':
|
||||
inc(L.bufpos, 2)
|
||||
elif L.buf[L.bufpos+1] == ')':
|
||||
tok.tokType = tkParDotRi
|
||||
Inc(L.bufpos, 2)
|
||||
inc(L.bufpos, 2)
|
||||
else:
|
||||
getOperator(L, tok)
|
||||
of '{':
|
||||
Inc(L.bufpos)
|
||||
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
|
||||
tok.toktype = tkCurlyDotLe
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
|
||||
tok.tokType = tkCurlyDotLe
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.toktype = tkCurlyLe
|
||||
tok.tokType = tkCurlyLe
|
||||
of '}':
|
||||
tok.toktype = tkCurlyRi
|
||||
Inc(L.bufpos)
|
||||
tok.tokType = tkCurlyRi
|
||||
inc(L.bufpos)
|
||||
of ';':
|
||||
tok.toktype = tkSemiColon
|
||||
Inc(L.bufpos)
|
||||
tok.tokType = tkSemiColon
|
||||
inc(L.bufpos)
|
||||
of '`':
|
||||
tok.tokType = tkAccent
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '\"':
|
||||
# check for extended raw string literal:
|
||||
var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
|
||||
@@ -796,12 +826,12 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
if c in OpChars:
|
||||
getOperator(L, tok)
|
||||
elif c == nimlexbase.EndOfFile:
|
||||
tok.toktype = tkEof
|
||||
tok.tokType = tkEof
|
||||
tok.indent = 0
|
||||
else:
|
||||
tok.literal = $c
|
||||
tok.tokType = tkInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
Inc(L.bufpos)
|
||||
|
||||
inc(L.bufpos)
|
||||
|
||||
dummyIdent = getIdent("")
|
||||
|
||||
@@ -20,17 +20,17 @@ type
|
||||
PStrEntry* = ref TStrEntry
|
||||
TLinkedList* = object # for the "find" operation:
|
||||
head*, tail*: PListEntry
|
||||
Counter*: int
|
||||
counter*: int
|
||||
|
||||
TCompareProc* = proc (entry: PListEntry, closure: Pointer): bool {.nimcall.}
|
||||
TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.}
|
||||
|
||||
proc InitLinkedList*(list: var TLinkedList) =
|
||||
list.Counter = 0
|
||||
proc initLinkedList*(list: var TLinkedList) =
|
||||
list.counter = 0
|
||||
list.head = nil
|
||||
list.tail = nil
|
||||
|
||||
proc Append*(list: var TLinkedList, entry: PListEntry) =
|
||||
Inc(list.counter)
|
||||
proc append*(list: var TLinkedList, entry: PListEntry) =
|
||||
inc(list.counter)
|
||||
entry.next = nil
|
||||
entry.prev = list.tail
|
||||
if list.tail != nil:
|
||||
@@ -39,7 +39,7 @@ proc Append*(list: var TLinkedList, entry: PListEntry) =
|
||||
list.tail = entry
|
||||
if list.head == nil: list.head = entry
|
||||
|
||||
proc Contains*(list: TLinkedList, data: string): bool =
|
||||
proc contains*(list: TLinkedList, data: string): bool =
|
||||
var it = list.head
|
||||
while it != nil:
|
||||
if PStrEntry(it).data == data:
|
||||
@@ -50,15 +50,15 @@ proc newStrEntry(data: string): PStrEntry =
|
||||
new(result)
|
||||
result.data = data
|
||||
|
||||
proc AppendStr*(list: var TLinkedList, data: string) =
|
||||
proc appendStr*(list: var TLinkedList, data: string) =
|
||||
append(list, newStrEntry(data))
|
||||
|
||||
proc IncludeStr*(list: var TLinkedList, data: string): bool =
|
||||
if Contains(list, data): return true
|
||||
AppendStr(list, data) # else: add to list
|
||||
proc includeStr*(list: var TLinkedList, data: string): bool =
|
||||
if contains(list, data): return true
|
||||
appendStr(list, data) # else: add to list
|
||||
|
||||
proc Prepend*(list: var TLinkedList, entry: PListEntry) =
|
||||
Inc(list.counter)
|
||||
proc prepend*(list: var TLinkedList, entry: PListEntry) =
|
||||
inc(list.counter)
|
||||
entry.prev = nil
|
||||
entry.next = list.head
|
||||
if list.head != nil:
|
||||
@@ -67,22 +67,22 @@ proc Prepend*(list: var TLinkedList, entry: PListEntry) =
|
||||
list.head = entry
|
||||
if list.tail == nil: list.tail = entry
|
||||
|
||||
proc PrependStr*(list: var TLinkedList, data: string) =
|
||||
proc prependStr*(list: var TLinkedList, data: string) =
|
||||
prepend(list, newStrEntry(data))
|
||||
|
||||
proc InsertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
|
||||
proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
|
||||
assert(pos != nil)
|
||||
if pos == list.head:
|
||||
prepend(list, entry)
|
||||
else:
|
||||
Inc(list.counter)
|
||||
inc(list.counter)
|
||||
entry.next = pos
|
||||
entry.prev = pos.prev
|
||||
if pos.prev != nil: pos.prev.next = entry
|
||||
pos.prev = entry
|
||||
|
||||
proc Remove*(list: var TLinkedList, entry: PListEntry) =
|
||||
Dec(list.counter)
|
||||
proc remove*(list: var TLinkedList, entry: PListEntry) =
|
||||
dec(list.counter)
|
||||
if entry == list.tail:
|
||||
list.tail = entry.prev
|
||||
if entry == list.head:
|
||||
@@ -91,22 +91,26 @@ proc Remove*(list: var TLinkedList, entry: PListEntry) =
|
||||
if entry.prev != nil: entry.prev.next = entry.next
|
||||
|
||||
proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
|
||||
if entry == list.head: return
|
||||
if entry == list.tail: list.tail = entry.prev
|
||||
if entry.next != nil: entry.next.prev = entry.prev
|
||||
if entry.prev != nil: entry.prev.next = entry.next
|
||||
entry.prev = nil
|
||||
entry.next = list.head
|
||||
list.head = entry
|
||||
when true:
|
||||
list.remove entry
|
||||
list.prepend entry
|
||||
else:
|
||||
if entry == list.head: return
|
||||
if entry == list.tail: list.tail = entry.prev
|
||||
if entry.next != nil: entry.next.prev = entry.prev
|
||||
if entry.prev != nil: entry.prev.next = entry.next
|
||||
entry.prev = nil
|
||||
entry.next = list.head
|
||||
list.head = entry
|
||||
|
||||
proc ExcludeStr*(list: var TLinkedList, data: string) =
|
||||
proc excludeStr*(list: var TLinkedList, data: string) =
|
||||
var it = list.head
|
||||
while it != nil:
|
||||
let nxt = it.next
|
||||
if PStrEntry(it).data == data: remove(list, it)
|
||||
it = nxt
|
||||
|
||||
proc Find*(list: TLinkedList, fn: TCompareProc, closure: Pointer): PListEntry =
|
||||
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
|
||||
result = list.head
|
||||
while result != nil:
|
||||
if fn(result, closure): return
|
||||
|
||||
@@ -23,63 +23,63 @@ type
|
||||
llsStdIn # stream encapsulates stdin
|
||||
TLLStream* = object of TObject
|
||||
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
|
||||
f*: tfile
|
||||
f*: TFile
|
||||
s*: string
|
||||
rd*, wr*: int # for string streams
|
||||
lineOffset*: int # for fake stdin line numbers
|
||||
|
||||
PLLStream* = ref TLLStream
|
||||
|
||||
proc LLStreamOpen*(data: string): PLLStream
|
||||
proc LLStreamOpen*(f: var tfile): PLLStream
|
||||
proc LLStreamOpen*(filename: string, mode: TFileMode): PLLStream
|
||||
proc LLStreamOpen*(): PLLStream
|
||||
proc LLStreamOpenStdIn*(): PLLStream
|
||||
proc LLStreamClose*(s: PLLStream)
|
||||
proc LLStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
|
||||
proc LLStreamReadLine*(s: PLLStream, line: var string): bool
|
||||
proc LLStreamReadAll*(s: PLLStream): string
|
||||
proc LLStreamWrite*(s: PLLStream, data: string)
|
||||
proc LLStreamWrite*(s: PLLStream, data: Char)
|
||||
proc LLStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
|
||||
proc LLStreamWriteln*(s: PLLStream, data: string)
|
||||
proc llStreamOpen*(data: string): PLLStream
|
||||
proc llStreamOpen*(f: var TFile): PLLStream
|
||||
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
|
||||
proc llStreamOpen*(): PLLStream
|
||||
proc llStreamOpenStdIn*(): PLLStream
|
||||
proc llStreamClose*(s: PLLStream)
|
||||
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
|
||||
proc llStreamReadLine*(s: PLLStream, line: var string): bool
|
||||
proc llStreamReadAll*(s: PLLStream): string
|
||||
proc llStreamWrite*(s: PLLStream, data: string)
|
||||
proc llStreamWrite*(s: PLLStream, data: char)
|
||||
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
|
||||
proc llStreamWriteln*(s: PLLStream, data: string)
|
||||
# implementation
|
||||
|
||||
proc LLStreamOpen(data: string): PLLStream =
|
||||
proc llStreamOpen(data: string): PLLStream =
|
||||
new(result)
|
||||
result.s = data
|
||||
result.kind = llsString
|
||||
|
||||
proc LLStreamOpen(f: var tfile): PLLStream =
|
||||
proc llStreamOpen(f: var TFile): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
||||
proc LLStreamOpen(filename: string, mode: TFileMode): PLLStream =
|
||||
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
if not open(result.f, filename, mode): result = nil
|
||||
|
||||
proc LLStreamOpen(): PLLStream =
|
||||
proc llStreamOpen(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsNone
|
||||
|
||||
proc LLStreamOpenStdIn(): PLLStream =
|
||||
proc llStreamOpenStdIn(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsStdIn
|
||||
result.s = ""
|
||||
result.lineOffset = -1
|
||||
|
||||
proc LLStreamClose(s: PLLStream) =
|
||||
proc llStreamClose(s: PLLStream) =
|
||||
case s.kind
|
||||
of llsNone, llsString, llsStdIn:
|
||||
nil
|
||||
discard
|
||||
of llsFile:
|
||||
close(s.f)
|
||||
|
||||
when not defined(ReadLineFromStdin):
|
||||
when not defined(readLineFromStdin):
|
||||
# fallback implementation:
|
||||
proc ReadLineFromStdin(prompt: string, line: var string): bool =
|
||||
proc readLineFromStdin(prompt: string, line: var string): bool =
|
||||
stdout.write(prompt)
|
||||
result = readLine(stdin, line)
|
||||
|
||||
@@ -99,7 +99,7 @@ proc endsWithOpr*(x: string): bool =
|
||||
result = x.endsWith(LineContinuationOprs)
|
||||
|
||||
proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
||||
result = inTriplestring or
|
||||
result = inTripleString or
|
||||
line[0] == ' ' or
|
||||
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
|
||||
|
||||
@@ -111,12 +111,12 @@ proc countTriples(s: string): int =
|
||||
inc i, 2
|
||||
inc i
|
||||
|
||||
proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
s.s = ""
|
||||
s.rd = 0
|
||||
var line = newStringOfCap(120)
|
||||
var triples = 0
|
||||
while ReadLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
|
||||
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
|
||||
add(s.s, line)
|
||||
add(s.s, "\n")
|
||||
inc triples, countTriples(line)
|
||||
@@ -127,7 +127,7 @@ proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
copyMem(buf, addr(s.s[s.rd]), result)
|
||||
inc(s.rd, result)
|
||||
|
||||
proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
case s.kind
|
||||
of llsNone:
|
||||
result = 0
|
||||
@@ -139,9 +139,9 @@ proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
of llsFile:
|
||||
result = readBuffer(s.f, buf, bufLen)
|
||||
of llsStdIn:
|
||||
result = LLreadFromStdin(s, buf, bufLen)
|
||||
result = llReadFromStdin(s, buf, bufLen)
|
||||
|
||||
proc LLStreamReadLine(s: PLLStream, line: var string): bool =
|
||||
proc llStreamReadLine(s: PLLStream, line: var string): bool =
|
||||
setLen(line, 0)
|
||||
case s.kind
|
||||
of llsNone:
|
||||
@@ -165,25 +165,25 @@ proc LLStreamReadLine(s: PLLStream, line: var string): bool =
|
||||
of llsStdIn:
|
||||
result = readLine(stdin, line)
|
||||
|
||||
proc LLStreamWrite(s: PLLStream, data: string) =
|
||||
proc llStreamWrite(s: PLLStream, data: string) =
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
nil
|
||||
discard
|
||||
of llsString:
|
||||
add(s.s, data)
|
||||
inc(s.wr, len(data))
|
||||
of llsFile:
|
||||
write(s.f, data)
|
||||
|
||||
proc LLStreamWriteln(s: PLLStream, data: string) =
|
||||
LLStreamWrite(s, data)
|
||||
LLStreamWrite(s, "\n")
|
||||
proc llStreamWriteln(s: PLLStream, data: string) =
|
||||
llStreamWrite(s, data)
|
||||
llStreamWrite(s, "\n")
|
||||
|
||||
proc LLStreamWrite(s: PLLStream, data: Char) =
|
||||
proc llStreamWrite(s: PLLStream, data: char) =
|
||||
var c: char
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
nil
|
||||
discard
|
||||
of llsString:
|
||||
add(s.s, data)
|
||||
inc(s.wr)
|
||||
@@ -191,22 +191,21 @@ proc LLStreamWrite(s: PLLStream, data: Char) =
|
||||
c = data
|
||||
discard writeBuffer(s.f, addr(c), sizeof(c))
|
||||
|
||||
proc LLStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
|
||||
proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
nil
|
||||
discard
|
||||
of llsString:
|
||||
if bufLen > 0:
|
||||
setlen(s.s, len(s.s) + bufLen)
|
||||
copyMem(addr(s.s[0 + s.wr]), buf, bufLen)
|
||||
inc(s.wr, bufLen)
|
||||
if buflen > 0:
|
||||
setLen(s.s, len(s.s) + buflen)
|
||||
copyMem(addr(s.s[0 + s.wr]), buf, buflen)
|
||||
inc(s.wr, buflen)
|
||||
of llsFile:
|
||||
discard writeBuffer(s.f, buf, bufLen)
|
||||
discard writeBuffer(s.f, buf, buflen)
|
||||
|
||||
proc LLStreamReadAll(s: PLLStream): string =
|
||||
proc llStreamReadAll(s: PLLStream): string =
|
||||
const
|
||||
bufSize = 2048
|
||||
var bytes, i: int
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
result = ""
|
||||
@@ -216,10 +215,10 @@ proc LLStreamReadAll(s: PLLStream): string =
|
||||
s.rd = len(s.s)
|
||||
of llsFile:
|
||||
result = newString(bufSize)
|
||||
bytes = readBuffer(s.f, addr(result[0]), bufSize)
|
||||
i = bytes
|
||||
var bytes = readBuffer(s.f, addr(result[0]), bufSize)
|
||||
var i = bytes
|
||||
while bytes == bufSize:
|
||||
setlen(result, i + bufSize)
|
||||
setLen(result, i + bufSize)
|
||||
bytes = readBuffer(s.f, addr(result[i + 0]), bufSize)
|
||||
inc(i, bytes)
|
||||
setlen(result, i)
|
||||
setLen(result, i)
|
||||
|
||||
@@ -21,7 +21,7 @@ proc considerAcc*(n: PNode): PIdent =
|
||||
of nkSym: result = n.sym.name
|
||||
of nkAccQuoted:
|
||||
case n.len
|
||||
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||
of 0: globalError(n.info, errIdentifierExpected, renderTree(n))
|
||||
of 1: result = considerAcc(n.sons[0])
|
||||
else:
|
||||
var id = ""
|
||||
@@ -30,16 +30,17 @@ proc considerAcc*(n: PNode): PIdent =
|
||||
case x.kind
|
||||
of nkIdent: id.add(x.ident.s)
|
||||
of nkSym: id.add(x.sym.name.s)
|
||||
else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||
else: globalError(n.info, errIdentifierExpected, renderTree(n))
|
||||
result = getIdent(id)
|
||||
of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
|
||||
else:
|
||||
GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||
globalError(n.info, errIdentifierExpected, renderTree(n))
|
||||
|
||||
template addSym*(scope: PScope, s: PSym) =
|
||||
StrTableAdd(scope.symbols, s)
|
||||
strTableAdd(scope.symbols, s)
|
||||
|
||||
proc addUniqueSym*(scope: PScope, s: PSym): TResult =
|
||||
if StrTableIncl(scope.symbols, s):
|
||||
if strTableIncl(scope.symbols, s):
|
||||
result = Failure
|
||||
else:
|
||||
result = Success
|
||||
@@ -64,17 +65,17 @@ iterator walkScopes*(scope: PScope): PScope =
|
||||
current = current.parent
|
||||
|
||||
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
|
||||
result = StrTableGet(c.currentScope.symbols, s)
|
||||
result = strTableGet(c.currentScope.symbols, s)
|
||||
|
||||
proc searchInScopes*(c: PContext, s: PIdent): PSym =
|
||||
for scope in walkScopes(c.currentScope):
|
||||
result = StrTableGet(scope.symbols, s)
|
||||
result = strTableGet(scope.symbols, s)
|
||||
if result != nil: return
|
||||
result = nil
|
||||
|
||||
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
|
||||
for scope in walkScopes(c.currentScope):
|
||||
result = StrTableGet(scope.symbols, s)
|
||||
result = strTableGet(scope.symbols, s)
|
||||
if result != nil and result.kind in filter: return
|
||||
result = nil
|
||||
|
||||
@@ -91,7 +92,8 @@ proc errorSym*(c: PContext, n: PNode): PSym =
|
||||
result.typ = errorType(c)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# pretend it's imported from some unknown module to prevent cascading errors:
|
||||
c.importTable.addSym(result)
|
||||
if gCmd != cmdInteractive and c.inCompilesContext == 0:
|
||||
c.importTable.addSym(result)
|
||||
|
||||
type
|
||||
TOverloadIterMode* = enum
|
||||
@@ -107,71 +109,74 @@ type
|
||||
|
||||
proc getSymRepr*(s: PSym): string =
|
||||
case s.kind
|
||||
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
|
||||
of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
|
||||
else: result = s.name.s
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
|
||||
# check if all symbols have been used and defined:
|
||||
var it: TTabIter
|
||||
var s = InitTabIter(it, scope.symbols)
|
||||
var s = initTabIter(it, scope.symbols)
|
||||
var missingImpls = 0
|
||||
while s != nil:
|
||||
if sfForward in s.flags:
|
||||
# too many 'implementation of X' errors are annoying
|
||||
# and slow 'suggest' down:
|
||||
if missingImpls == 0:
|
||||
LocalError(s.info, errImplOfXexpected, getSymRepr(s))
|
||||
localError(s.info, errImplOfXexpected, getSymRepr(s))
|
||||
inc missingImpls
|
||||
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
|
||||
# BUGFIX: check options in s!
|
||||
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
|
||||
Message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
|
||||
s = NextIter(it, scope.symbols)
|
||||
# XXX: implicit type params are currently skTypes
|
||||
# maybe they can be made skGenericParam as well.
|
||||
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
|
||||
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
|
||||
s = nextIter(it, scope.symbols)
|
||||
|
||||
proc WrongRedefinition*(info: TLineInfo, s: string) =
|
||||
proc wrongRedefinition*(info: TLineInfo, s: string) =
|
||||
if gCmd != cmdInteractive:
|
||||
localError(info, errAttemptToRedefine, s)
|
||||
|
||||
proc addDecl*(c: PContext, sym: PSym) =
|
||||
if c.currentScope.addUniqueSym(sym) == Failure:
|
||||
WrongRedefinition(sym.info, sym.Name.s)
|
||||
wrongRedefinition(sym.info, sym.name.s)
|
||||
|
||||
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
||||
discard c.currentScope.addUniqueSym(sym)
|
||||
|
||||
proc addDeclAt*(scope: PScope, sym: PSym) =
|
||||
if scope.addUniqueSym(sym) == Failure:
|
||||
WrongRedefinition(sym.info, sym.Name.s)
|
||||
wrongRedefinition(sym.info, sym.name.s)
|
||||
|
||||
proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
if sfExported in sym.flags:
|
||||
# add to interface:
|
||||
if c.module != nil: StrTableAdd(c.module.tab, sym)
|
||||
else: InternalError(sym.info, "AddInterfaceDeclAux")
|
||||
if c.module != nil: strTableAdd(c.module.tab, sym)
|
||||
else: internalError(sym.info, "AddInterfaceDeclAux")
|
||||
|
||||
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
addDeclAt(scope, sym)
|
||||
AddInterfaceDeclAux(c, sym)
|
||||
addInterfaceDeclAux(c, sym)
|
||||
|
||||
proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
|
||||
if fn.kind notin OverloadableSyms:
|
||||
InternalError(fn.info, "addOverloadableSymAt")
|
||||
internalError(fn.info, "addOverloadableSymAt")
|
||||
return
|
||||
var check = StrTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.Kind notin OverloadableSyms:
|
||||
WrongRedefinition(fn.info, fn.Name.s)
|
||||
var check = strTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.kind notin OverloadableSyms:
|
||||
wrongRedefinition(fn.info, fn.name.s)
|
||||
else:
|
||||
scope.addSym(fn)
|
||||
|
||||
proc addInterfaceDecl*(c: PContext, sym: PSym) =
|
||||
# it adds the symbol to the interface if appropriate
|
||||
addDecl(c, sym)
|
||||
AddInterfaceDeclAux(c, sym)
|
||||
addInterfaceDeclAux(c, sym)
|
||||
|
||||
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
# it adds the symbol to the interface if appropriate
|
||||
addOverloadableSymAt(scope, sym)
|
||||
AddInterfaceDeclAux(c, sym)
|
||||
addInterfaceDeclAux(c, sym)
|
||||
|
||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
# Looks up a symbol. Generates an error in case of nil.
|
||||
@@ -179,7 +184,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
of nkIdent:
|
||||
result = searchInScopes(c, n.ident)
|
||||
if result == nil:
|
||||
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||
localError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||
result = errorSym(c, n)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
@@ -187,34 +192,34 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
var ident = considerAcc(n)
|
||||
result = searchInScopes(c, ident)
|
||||
if result == nil:
|
||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n)
|
||||
else:
|
||||
InternalError(n.info, "lookUp")
|
||||
internalError(n.info, "lookUp")
|
||||
return
|
||||
if Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, result.name.s)
|
||||
if contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, result.name.s)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
|
||||
type
|
||||
TLookupFlag* = enum
|
||||
checkAmbiguity, checkUndeclared
|
||||
|
||||
proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
var ident = considerAcc(n)
|
||||
result = searchInScopes(c, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n)
|
||||
elif checkAmbiguity in flags and result != nil and
|
||||
Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, ident.s)
|
||||
contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, ident.s)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, n.sym.name.s)
|
||||
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, n.sym.name.s)
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
||||
@@ -226,28 +231,31 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
ident = considerAcc(n.sons[1])
|
||||
if ident != nil:
|
||||
if m == c.module:
|
||||
result = StrTableGet(c.topLevelScope.symbols, ident)
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
result = StrTableGet(m.tab, ident)
|
||||
result = strTableGet(m.tab, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n.sons[1])
|
||||
elif checkUndeclared in flags:
|
||||
LocalError(n.sons[1].info, errIdentifierExpected,
|
||||
elif n.sons[1].kind == nkSym:
|
||||
result = n.sons[1].sym
|
||||
elif checkUndeclared in flags and
|
||||
n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
|
||||
localError(n.sons[1].info, errIdentifierExpected,
|
||||
renderTree(n.sons[1]))
|
||||
result = errorSym(c, n.sons[1])
|
||||
else:
|
||||
result = nil
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
var ident = considerAcc(n)
|
||||
o.scope = c.currentScope
|
||||
o.mode = oimNoQualifier
|
||||
while true:
|
||||
result = InitIdentIter(o.it, o.scope.symbols, ident)
|
||||
result = initIdentIter(o.it, o.scope.symbols, ident)
|
||||
if result != nil:
|
||||
break
|
||||
else:
|
||||
@@ -268,12 +276,12 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if ident != nil:
|
||||
if o.m == c.module:
|
||||
# a module may access its private members:
|
||||
result = InitIdentIter(o.it, c.topLevelScope.symbols, ident)
|
||||
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
|
||||
o.mode = oimSelfModule
|
||||
else:
|
||||
result = InitIdentIter(o.it, o.m.tab, ident)
|
||||
result = initIdentIter(o.it, o.m.tab, ident)
|
||||
else:
|
||||
LocalError(n.sons[1].info, errIdentifierExpected,
|
||||
localError(n.sons[1].info, errIdentifierExpected,
|
||||
renderTree(n.sons[1]))
|
||||
result = errorSym(c, n.sons[1])
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
@@ -281,8 +289,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
result = n.sons[0].sym
|
||||
o.symChoiceIndex = 1
|
||||
o.inSymChoice = initIntSet()
|
||||
Incl(o.inSymChoice, result.id)
|
||||
else: nil
|
||||
incl(o.inSymChoice, result.id)
|
||||
else: discard
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
proc lastOverloadScope*(o: TOverloadIter): int =
|
||||
@@ -302,7 +310,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
while result == nil:
|
||||
o.scope = o.scope.parent
|
||||
if o.scope == nil: break
|
||||
result = InitIdentIter(o.it, o.scope.symbols, o.it.name)
|
||||
result = initIdentIter(o.it, o.scope.symbols, o.it.name)
|
||||
# BUGFIX: o.it.name <-> n.ident
|
||||
else:
|
||||
result = nil
|
||||
@@ -313,26 +321,38 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
of oimSymChoice:
|
||||
if o.symChoiceIndex < sonsLen(n):
|
||||
result = n.sons[o.symChoiceIndex].sym
|
||||
Incl(o.inSymChoice, result.id)
|
||||
incl(o.inSymChoice, result.id)
|
||||
inc o.symChoiceIndex
|
||||
elif n.kind == nkOpenSymChoice:
|
||||
# try 'local' symbols too for Koenig's lookup:
|
||||
o.mode = oimSymChoiceLocalLookup
|
||||
o.scope = c.currentScope
|
||||
result = FirstIdentExcluding(o.it, o.scope.symbols,
|
||||
result = firstIdentExcluding(o.it, o.scope.symbols,
|
||||
n.sons[0].sym.name, o.inSymChoice)
|
||||
while result == nil:
|
||||
o.scope = o.scope.parent
|
||||
if o.scope == nil: break
|
||||
result = FirstIdentExcluding(o.it, o.scope.symbols,
|
||||
result = firstIdentExcluding(o.it, o.scope.symbols,
|
||||
n.sons[0].sym.name, o.inSymChoice)
|
||||
of oimSymChoiceLocalLookup:
|
||||
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
|
||||
while result == nil:
|
||||
o.scope = o.scope.parent
|
||||
if o.scope == nil: break
|
||||
result = FirstIdentExcluding(o.it, o.scope.symbols,
|
||||
result = firstIdentExcluding(o.it, o.scope.symbols,
|
||||
n.sons[0].sym.name, o.inSymChoice)
|
||||
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
|
||||
when false:
|
||||
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
|
||||
flags = {checkUndeclared}): PSym =
|
||||
var o: TOverloadIter
|
||||
result = initOverloadIter(o, c, n)
|
||||
var a = result
|
||||
while a != nil:
|
||||
if sfImmediate in a.flags: return a
|
||||
a = nextOverloadIter(o, c, n)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
localError(n.info, errUndeclaredIdentifier, n.considerAcc.s)
|
||||
result = errorSym(c, n)
|
||||
|
||||
228
compiler/lowerings.nim
Normal file
228
compiler/lowerings.nim
Normal file
@@ -0,0 +1,228 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements common simple lowerings.
|
||||
|
||||
const
|
||||
genPrefix* = ":tmp" # prefix for generated names
|
||||
|
||||
import ast, astalgo, types, idents, magicsys, msgs, options
|
||||
|
||||
proc newTupleAccess*(tup: PNode, i: int): PNode =
|
||||
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
|
||||
abstractInst).sons[i])
|
||||
addSon(result, copyTree(tup))
|
||||
var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
|
||||
lit.intVal = i
|
||||
addSon(result, lit)
|
||||
|
||||
proc addVar*(father, v: PNode) =
|
||||
var vpart = newNodeI(nkIdentDefs, v.info, 3)
|
||||
vpart.sons[0] = v
|
||||
vpart.sons[1] = ast.emptyNode
|
||||
vpart.sons[2] = ast.emptyNode
|
||||
addSon(father, vpart)
|
||||
|
||||
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 =
|
||||
result = newNodeI(nkFastAsgn, le.info, 2)
|
||||
result.sons[0] = le
|
||||
result.sons[1] = ri
|
||||
|
||||
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
||||
assert n.kind == nkVarTuple
|
||||
let value = n.lastSon
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, value.info)
|
||||
v.addVar(newSymNode(temp))
|
||||
result.add(v)
|
||||
|
||||
result.add newAsgnStmt(newSymNode(temp), value)
|
||||
for i in 0 .. n.len-3:
|
||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
||||
|
||||
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||
result = newType(tyObject, owner)
|
||||
rawAddSon(result, nil)
|
||||
incl result.flags, tfFinal
|
||||
result.n = newNodeI(nkRecList, info)
|
||||
|
||||
proc addField*(obj: PType; s: PSym) =
|
||||
# because of 'gensym' support, we have to mangle the name with its ID.
|
||||
# This is hacky but the clean solution is much more complex than it looks.
|
||||
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
|
||||
let t = skipIntLit(s.typ)
|
||||
field.typ = t
|
||||
field.position = sonsLen(obj.n)
|
||||
addSon(obj.n, newSymNode(field))
|
||||
|
||||
proc newDotExpr(obj, b: PSym): PNode =
|
||||
result = newNodeI(nkDotExpr, obj.info)
|
||||
let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
|
||||
assert field != nil, b.name.s
|
||||
addSon(result, newSymNode(obj))
|
||||
addSon(result, newSymNode(field))
|
||||
result.typ = field.typ
|
||||
|
||||
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||
# returns a[].b as a node
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = a.typ.sons[0]
|
||||
assert deref.typ.kind == tyObject
|
||||
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
|
||||
assert field != nil, b.name.s
|
||||
addSon(deref, a)
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
addSon(result, deref)
|
||||
addSon(result, newSymNode(field))
|
||||
result.typ = field.typ
|
||||
|
||||
proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
|
||||
result = indirectAccess(newSymNode(a), b, info)
|
||||
|
||||
proc genAddrOf*(n: PNode): PNode =
|
||||
result = newNodeI(nkAddr, n.info, 1)
|
||||
result.sons[0] = n
|
||||
result.typ = newType(tyPtr, n.typ.owner)
|
||||
result.typ.rawAddSon(n.typ)
|
||||
|
||||
proc callCodegenProc*(name: string, arg1: PNode;
|
||||
arg2, arg3: PNode = nil): PNode =
|
||||
result = newNodeI(nkCall, arg1.info)
|
||||
let sym = magicsys.getCompilerProc(name)
|
||||
if sym == nil:
|
||||
localError(arg1.info, errSystemNeeds, name)
|
||||
else:
|
||||
result.add newSymNode(sym)
|
||||
result.add arg1
|
||||
if arg2 != nil: result.add arg2
|
||||
if arg3 != nil: result.add arg3
|
||||
|
||||
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||
varSection, call: PNode): PSym =
|
||||
var body = newNodeI(nkStmtList, f.info)
|
||||
body.add varSection
|
||||
body.add callCodeGenProc("nimArgsPassingDone", newSymNode(threadParam))
|
||||
body.add call
|
||||
|
||||
var params = newNodeI(nkFormalParams, f.info)
|
||||
params.add emptyNode
|
||||
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(name), argsParam.owner, f.info)
|
||||
result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
|
||||
result.typ = t
|
||||
|
||||
proc createCastExpr(argsParam: PSym; objType: PType): PNode =
|
||||
result = newNodeI(nkCast, argsParam.info)
|
||||
result.add emptyNode
|
||||
result.add newSymNode(argsParam)
|
||||
result.typ = newType(tyPtr, objType.owner)
|
||||
result.typ.rawAddSon(objType)
|
||||
|
||||
proc wrapProcForSpawn*(owner: PSym; n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
if n.kind notin nkCallKinds or not n.typ.isEmptyType:
|
||||
localError(n.info, "'spawn' takes a call expression of type void")
|
||||
return
|
||||
if optThreadAnalysis in gGlobalOptions:
|
||||
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
|
||||
localError(n.info, "'spawn' takes a GC safe call expression")
|
||||
var
|
||||
threadParam = newSym(skParam, getIdent"thread", owner, n.info)
|
||||
argsParam = newSym(skParam, getIdent"args", owner, n.info)
|
||||
block:
|
||||
let ptrType = getSysType(tyPointer)
|
||||
threadParam.typ = ptrType
|
||||
argsParam.typ = ptrType
|
||||
argsParam.position = 1
|
||||
var objType = createObj(owner, n.info)
|
||||
incl(objType.flags, tfFinal)
|
||||
let castExpr = createCastExpr(argsParam, objType)
|
||||
|
||||
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
|
||||
block:
|
||||
scratchObj.typ = objType
|
||||
incl(scratchObj.flags, sfFromGeneric)
|
||||
var varSectionB = newNodeI(nkVarSection, n.info)
|
||||
varSectionB.addVar(scratchObj.newSymNode)
|
||||
result.add varSectionB
|
||||
|
||||
var call = newNodeI(nkCall, n.info)
|
||||
var fn = n.sons[0]
|
||||
# templates and macros are in fact valid here due to the nature of
|
||||
# the transformation:
|
||||
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
|
||||
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"fn", owner, n.info)
|
||||
field.typ = argType
|
||||
objType.addField(field)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
|
||||
fn = indirectAccess(castExpr, field, n.info)
|
||||
elif fn.kind == nkSym and fn.sym.kind in {skClosureIterator, skIterator}:
|
||||
localError(n.info, "iterator in spawn environment is not allowed")
|
||||
elif fn.typ.callConv == ccClosure:
|
||||
localError(n.info, "closure in spawn environment is not allowed")
|
||||
|
||||
call.add(fn)
|
||||
var varSection = newNodeI(nkVarSection, n.info)
|
||||
let formals = n[0].typ.n
|
||||
let tmpName = getIdent(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 == tyVar:
|
||||
localError(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, owner, n.info)
|
||||
field.typ = argType
|
||||
objType.addField(field)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
||||
|
||||
var temp = newSym(skTemp, tmpName, owner, n.info)
|
||||
temp.typ = argType
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, n.info, 3)
|
||||
vpart.sons[0] = newSymNode(temp)
|
||||
vpart.sons[1] = ast.emptyNode
|
||||
vpart.sons[2] = indirectAccess(castExpr, field, n.info)
|
||||
varSection.add vpart
|
||||
|
||||
call.add(newSymNode(temp))
|
||||
|
||||
let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, call)
|
||||
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
||||
genAddrOf(scratchObj.newSymNode))
|
||||
@@ -12,14 +12,14 @@
|
||||
import
|
||||
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
|
||||
|
||||
var SystemModule*: PSym
|
||||
var systemModule*: PSym
|
||||
|
||||
proc registerSysType*(t: PType)
|
||||
# magic symbols in the system module:
|
||||
proc getSysType*(kind: TTypeKind): PType
|
||||
proc getCompilerProc*(name: string): PSym
|
||||
proc registerCompilerProc*(s: PSym)
|
||||
proc FinishSystem*(tab: TStrTable)
|
||||
proc finishSystem*(tab: TStrTable)
|
||||
proc getSysSym*(name: string): PSym
|
||||
# implementation
|
||||
|
||||
@@ -36,13 +36,25 @@ proc newSysType(kind: TTypeKind, size: int): PType =
|
||||
result.align = size
|
||||
|
||||
proc getSysSym(name: string): PSym =
|
||||
result = StrTableGet(systemModule.tab, getIdent(name))
|
||||
result = strTableGet(systemModule.tab, getIdent(name))
|
||||
if result == nil:
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
|
||||
proc getSysMagic*(name: string, m: TMagic): PSym =
|
||||
var ti: TIdentIter
|
||||
let id = getIdent(name)
|
||||
result = initIdentIter(ti, systemModule.tab, id)
|
||||
while result != nil:
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.magic == m: return result
|
||||
result = nextIdentIter(ti, systemModule.tab)
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, id, systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
|
||||
proc sysTypeFromName*(name: string): PType =
|
||||
result = getSysSym(name).typ
|
||||
|
||||
@@ -62,19 +74,19 @@ proc getSysType(kind: TTypeKind): PType =
|
||||
of tyUInt64: result = sysTypeFromName("uint64")
|
||||
of tyFloat: result = sysTypeFromName("float")
|
||||
of tyFloat32: result = sysTypeFromName("float32")
|
||||
of tyFloat64: result = sysTypeFromName("float64")
|
||||
of tyFloat64: return sysTypeFromName("float64")
|
||||
of tyFloat128: result = sysTypeFromName("float128")
|
||||
of tyBool: result = sysTypeFromName("bool")
|
||||
of tyChar: result = sysTypeFromName("char")
|
||||
of tyString: result = sysTypeFromName("string")
|
||||
of tyCstring: result = sysTypeFromName("cstring")
|
||||
of tyCString: result = sysTypeFromName("cstring")
|
||||
of tyPointer: result = sysTypeFromName("pointer")
|
||||
of tyNil: result = newSysType(tyNil, ptrSize)
|
||||
else: InternalError("request for typekind: " & $kind)
|
||||
else: internalError("request for typekind: " & $kind)
|
||||
gSysTypes[kind] = result
|
||||
if result.kind != kind:
|
||||
InternalError("wanted: " & $kind & " got: " & $result.kind)
|
||||
if result == nil: InternalError("type not found: " & $kind)
|
||||
internalError("wanted: " & $kind & " got: " & $result.kind)
|
||||
if result == nil: internalError("type not found: " & $kind)
|
||||
|
||||
var
|
||||
intTypeCache: array[-5..64, PType]
|
||||
@@ -103,19 +115,26 @@ proc getIntLitType*(literal: PNode): PType =
|
||||
result = copyType(ti, ti.owner, false)
|
||||
result.n = literal
|
||||
|
||||
proc skipIntLit*(t: PType): PType {.inline.} =
|
||||
if t.kind == tyInt and t.n != nil:
|
||||
result = getSysType(tyInt)
|
||||
else:
|
||||
result = t
|
||||
proc getFloatLitType*(literal: PNode): PType =
|
||||
# for now we do not cache these:
|
||||
result = newSysType(tyFloat, size=8)
|
||||
result.n = literal
|
||||
|
||||
proc AddSonSkipIntLit*(father, son: PType) =
|
||||
proc skipIntLit*(t: PType): PType {.inline.} =
|
||||
if t.n != nil:
|
||||
if t.kind in {tyInt, tyFloat}:
|
||||
return getSysType(t.kind)
|
||||
result = t
|
||||
|
||||
proc addSonSkipIntLit*(father, son: PType) =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son.skipIntLit)
|
||||
let s = son.skipIntLit
|
||||
add(father.sons, s)
|
||||
propagateToOwner(father, s)
|
||||
|
||||
proc setIntLitType*(result: PNode) =
|
||||
let i = result.intVal
|
||||
case platform.IntSize
|
||||
case platform.intSize
|
||||
of 8: result.typ = getIntLitType(result)
|
||||
of 4:
|
||||
if i >= low(int32) and i <= high(int32):
|
||||
@@ -139,13 +158,13 @@ proc setIntLitType*(result: PNode) =
|
||||
result.typ = getSysType(tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
else: InternalError(result.info, "invalid int size")
|
||||
else: internalError(result.info, "invalid int size")
|
||||
|
||||
proc getCompilerProc(name: string): PSym =
|
||||
var ident = getIdent(name, hashIgnoreStyle(name))
|
||||
result = StrTableGet(compilerprocs, ident)
|
||||
result = strTableGet(compilerprocs, ident)
|
||||
if result == nil:
|
||||
result = StrTableGet(rodCompilerProcs, ident)
|
||||
result = strTableGet(rodCompilerprocs, ident)
|
||||
if result != nil:
|
||||
strTableAdd(compilerprocs, result)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
@@ -153,7 +172,6 @@ proc getCompilerProc(name: string): PSym =
|
||||
proc registerCompilerProc(s: PSym) =
|
||||
strTableAdd(compilerprocs, s)
|
||||
|
||||
proc FinishSystem(tab: TStrTable) = nil
|
||||
|
||||
initStrTable(compilerprocs)
|
||||
proc finishSystem(tab: TStrTable) = discard
|
||||
|
||||
initStrTable(compilerprocs)
|
||||
|
||||
@@ -1,214 +1,31 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# implements the command dispatcher and several commands as well as the
|
||||
# module handling
|
||||
# implements the command dispatcher and several commands
|
||||
|
||||
import
|
||||
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
|
||||
os, lists, condsyms, rodread, rodwrite, ropes, trees, times,
|
||||
import
|
||||
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
|
||||
os, condsyms, rodread, rodwrite, times,
|
||||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||
cgen, jsgen, cgendata, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, evals, types, idgen,
|
||||
tables, docgen2, service, magicsys, parser, crc, ccgutils, sigmatch
|
||||
cgen, jsgen, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
|
||||
pretty
|
||||
|
||||
from magicsys import systemModule, resetSysTypes
|
||||
|
||||
const
|
||||
has_LLVM_Backend = false
|
||||
hasLLVM_Backend = false
|
||||
|
||||
when has_LLVM_Backend:
|
||||
when hasLLVM_Backend:
|
||||
import llvmgen
|
||||
|
||||
proc MainCommand*()
|
||||
|
||||
# ------------------ module handling -----------------------------------------
|
||||
|
||||
type
|
||||
TNeedRecompile = enum Maybe, No, Yes, Probing, Recompiled
|
||||
TCrcStatus = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged
|
||||
|
||||
TModuleInMemory = object
|
||||
compiledAt: float
|
||||
crc: TCrc32
|
||||
deps: seq[int32] ## XXX: slurped files are not currently tracked
|
||||
needsRecompile: TNeedRecompile
|
||||
crcStatus: TCrcStatus
|
||||
|
||||
var
|
||||
gCompiledModules: seq[PSym] = @[]
|
||||
gMemCacheData: seq[TModuleInMemory] = @[]
|
||||
## XXX: we should implement recycling of file IDs
|
||||
## if the user keeps renaming modules, the file IDs will keep growing
|
||||
|
||||
proc getModule(fileIdx: int32): PSym =
|
||||
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
||||
result = gCompiledModules[fileIdx]
|
||||
else:
|
||||
result = nil
|
||||
|
||||
template compiledAt(x: PSym): expr =
|
||||
gMemCacheData[x.position].compiledAt
|
||||
|
||||
template crc(x: PSym): expr =
|
||||
gMemCacheData[x.position].crc
|
||||
|
||||
proc crcChanged(fileIdx: int32): bool =
|
||||
InternalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
|
||||
|
||||
template updateStatus =
|
||||
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
|
||||
else: crcNotChanged
|
||||
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result
|
||||
|
||||
case gMemCacheData[fileIdx].crcStatus:
|
||||
of crcHasChanged:
|
||||
result = true
|
||||
of crcNotChanged:
|
||||
result = false
|
||||
of crcCached:
|
||||
let newCrc = crcFromFile(fileIdx.toFilename)
|
||||
result = newCrc != gMemCacheData[fileIdx].crc
|
||||
gMemCacheData[fileIdx].crc = newCrc
|
||||
updateStatus()
|
||||
of crcNotTaken:
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
result = true
|
||||
updateStatus()
|
||||
|
||||
proc doCRC(fileIdx: int32) =
|
||||
if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
|
||||
# echo "FIRST CRC: ", fileIdx.ToFilename
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
|
||||
proc addDep(x: Psym, dep: int32) =
|
||||
growCache gMemCacheData, dep
|
||||
gMemCacheData[x.position].deps.safeAdd(dep)
|
||||
|
||||
proc resetModule(fileIdx: int32) =
|
||||
# echo "HARD RESETTING ", fileIdx.toFilename
|
||||
gMemCacheData[fileIdx].needsRecompile = Yes
|
||||
gCompiledModules[fileIdx] = nil
|
||||
cgendata.gModules[fileIdx] = nil
|
||||
resetSourceMap(fileIdx)
|
||||
|
||||
proc resetAllModules =
|
||||
for i in 0..gCompiledModules.high:
|
||||
if gCompiledModules[i] != nil:
|
||||
resetModule(i.int32)
|
||||
|
||||
# for m in cgenModules(): echo "CGEN MODULE FOUND"
|
||||
|
||||
proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
||||
template markDirty =
|
||||
resetModule(fileIdx)
|
||||
return Yes
|
||||
|
||||
if gMemCacheData[fileIdx].needsRecompile != Maybe:
|
||||
return gMemCacheData[fileIdx].needsRecompile
|
||||
|
||||
if optForceFullMake in gGlobalOptions or
|
||||
crcChanged(fileIdx):
|
||||
markDirty
|
||||
|
||||
if gMemCacheData[fileIdx].deps != nil:
|
||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
||||
for dep in gMemCacheData[fileIdx].deps:
|
||||
let d = checkDepMem(dep)
|
||||
if d in { Yes, Recompiled }:
|
||||
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
|
||||
markDirty
|
||||
|
||||
gMemCacheData[fileIdx].needsRecompile = No
|
||||
return No
|
||||
|
||||
proc newModule(fileIdx: int32): PSym =
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
new(result)
|
||||
result.id = - 1 # for better error checking
|
||||
result.kind = skModule
|
||||
let filename = fileIdx.toFilename
|
||||
result.name = getIdent(splitFile(filename).name)
|
||||
if not isNimrodIdentifier(result.name.s):
|
||||
rawMessage(errInvalidModuleName, result.name.s)
|
||||
|
||||
result.owner = result # a module belongs to itself
|
||||
result.info = newLineInfo(fileIdx, 1, 1)
|
||||
result.position = fileIdx
|
||||
|
||||
growCache gMemCacheData, fileIdx
|
||||
growCache gCompiledModules, fileIdx
|
||||
gCompiledModules[result.position] = result
|
||||
|
||||
incl(result.flags, sfUsed)
|
||||
initStrTable(result.tab)
|
||||
StrTableAdd(result.tab, result) # a module knows itself
|
||||
|
||||
proc compileModule(fileIdx: int32, flags: TSymFlags): PSym =
|
||||
result = getModule(fileIdx)
|
||||
if result == nil:
|
||||
growCache gMemCacheData, fileIdx
|
||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
||||
result = newModule(fileIdx)
|
||||
#var rd = handleSymbolFile(result)
|
||||
var rd: PRodReader
|
||||
result.flags = result.flags + flags
|
||||
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
|
||||
rd = handleSymbolFile(result)
|
||||
if result.id < 0:
|
||||
InternalError("handleSymbolFile should have set the module\'s ID")
|
||||
return
|
||||
else:
|
||||
result.id = getID()
|
||||
processModule(result, nil, rd)
|
||||
if optCaasEnabled in gGlobalOptions:
|
||||
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
|
||||
gMemCacheData[fileIdx].needsRecompile = Recompiled
|
||||
doCRC fileIdx
|
||||
else:
|
||||
if checkDepMem(fileIdx) == Yes:
|
||||
result = CompileModule(fileIdx, flags)
|
||||
else:
|
||||
result = gCompiledModules[fileIdx]
|
||||
|
||||
proc importModule(s: PSym, fileIdx: int32): PSym =
|
||||
# this is called by the semantic checking phase
|
||||
result = compileModule(fileIdx, {})
|
||||
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
|
||||
if sfSystemModule in result.flags:
|
||||
LocalError(result.info, errAttemptToRedefine, result.Name.s)
|
||||
|
||||
proc includeModule(s: PSym, fileIdx: int32): PNode =
|
||||
result = syntaxes.parseFile(fileIdx)
|
||||
if optCaasEnabled in gGlobalOptions:
|
||||
growCache gMemCacheData, fileIdx
|
||||
addDep(s, fileIdx)
|
||||
doCrc(fileIdx)
|
||||
|
||||
proc `==^`(a, b: string): bool =
|
||||
try:
|
||||
result = sameFile(a, b)
|
||||
except EOS:
|
||||
result = false
|
||||
|
||||
proc compileSystemModule =
|
||||
if magicsys.SystemModule == nil:
|
||||
SystemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
||||
discard CompileModule(SystemFileIdx, {sfSystemModule})
|
||||
|
||||
proc CompileProject(projectFile = gProjectMainIdx) =
|
||||
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
||||
if projectFile == SystemFileIdx:
|
||||
discard CompileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
compileSystemModule()
|
||||
discard CompileModule(projectFile, {sfMainModule})
|
||||
|
||||
proc rodPass =
|
||||
if optSymbolFiles in gGlobalOptions:
|
||||
registerPass(rodwritePass)
|
||||
@@ -220,22 +37,22 @@ proc semanticPasses =
|
||||
registerPass verbosePass
|
||||
registerPass semPass
|
||||
|
||||
proc CommandGenDepend =
|
||||
proc commandGenDepend =
|
||||
semanticPasses()
|
||||
registerPass(genDependPass)
|
||||
registerPass(gendependPass)
|
||||
registerPass(cleanupPass)
|
||||
compileProject()
|
||||
generateDot(gProjectFull)
|
||||
execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
|
||||
' ' & changeFileExt(gProjectFull, "dot"))
|
||||
|
||||
proc CommandCheck =
|
||||
proc commandCheck =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
semanticPasses() # use an empty backend for semantic checking only
|
||||
rodPass()
|
||||
compileProject()
|
||||
|
||||
proc CommandDoc2 =
|
||||
proc commandDoc2 =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
semanticPasses()
|
||||
registerPass(docgen2Pass)
|
||||
@@ -243,7 +60,7 @@ proc CommandDoc2 =
|
||||
compileProject()
|
||||
finishDoc2Pass(gProjectName)
|
||||
|
||||
proc CommandCompileToC =
|
||||
proc commandCompileToC =
|
||||
semanticPasses()
|
||||
registerPass(cgenPass)
|
||||
rodPass()
|
||||
@@ -256,7 +73,7 @@ proc CommandCompileToC =
|
||||
compileProject()
|
||||
cgenWriteModules()
|
||||
if gCmd != cmdRun:
|
||||
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
|
||||
extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
|
||||
|
||||
if isServing:
|
||||
# caas will keep track only of the compilation commands
|
||||
@@ -281,7 +98,7 @@ proc CommandCompileToC =
|
||||
# rodread.rodcompilerProcs
|
||||
# rodread.gTypeTable
|
||||
# rodread.gMods
|
||||
|
||||
|
||||
# !! ropes.cache
|
||||
# semthreads.computed?
|
||||
#
|
||||
@@ -294,52 +111,45 @@ proc CommandCompileToC =
|
||||
ccgutils.resetCaches()
|
||||
GC_fullCollect()
|
||||
|
||||
when has_LLVM_Backend:
|
||||
proc CommandCompileToLLVM =
|
||||
when hasLLVM_Backend:
|
||||
proc commandCompileToLLVM =
|
||||
semanticPasses()
|
||||
registerPass(llvmgen.llvmgenPass())
|
||||
rodPass()
|
||||
#registerPass(cleanupPass())
|
||||
compileProject()
|
||||
|
||||
proc CommandCompileToJS =
|
||||
proc commandCompileToJS =
|
||||
#incl(gGlobalOptions, optSafeCode)
|
||||
setTarget(osJS, cpuJS)
|
||||
#initDefines()
|
||||
DefineSymbol("nimrod") # 'nimrod' is always defined
|
||||
DefineSymbol("ecmascript") # For backward compatibility
|
||||
DefineSymbol("js")
|
||||
defineSymbol("nimrod") # 'nimrod' is always defined
|
||||
defineSymbol("ecmascript") # For backward compatibility
|
||||
defineSymbol("js")
|
||||
semanticPasses()
|
||||
registerPass(jsgenPass)
|
||||
registerPass(JSgenPass)
|
||||
compileProject()
|
||||
|
||||
proc InteractivePasses =
|
||||
proc interactivePasses =
|
||||
#incl(gGlobalOptions, optSafeCode)
|
||||
#setTarget(osNimrodVM, cpuNimrodVM)
|
||||
initDefines()
|
||||
DefineSymbol("nimrodvm")
|
||||
when hasFFI: DefineSymbol("nimffi")
|
||||
defineSymbol("nimrodvm")
|
||||
when hasFFI: defineSymbol("nimffi")
|
||||
registerPass(verbosePass)
|
||||
registerPass(semPass)
|
||||
registerPass(evalPass)
|
||||
|
||||
var stdinModule: PSym
|
||||
proc makeStdinModule: PSym =
|
||||
if stdinModule == nil:
|
||||
stdinModule = newModule(fileInfoIdx"stdin")
|
||||
stdinModule.id = getID()
|
||||
result = stdinModule
|
||||
|
||||
proc CommandInteractive =
|
||||
proc commandInteractive =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
InteractivePasses()
|
||||
interactivePasses()
|
||||
compileSystemModule()
|
||||
if commandArgs.len > 0:
|
||||
discard CompileModule(fileInfoIdx(gProjectFull), {})
|
||||
discard compileModule(fileInfoIdx(gProjectFull), {})
|
||||
else:
|
||||
var m = makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
processModule(m, LLStreamOpenStdIn(), nil)
|
||||
processModule(m, llStreamOpenStdIn(), nil)
|
||||
|
||||
const evalPasses = [verbosePass, semPass, evalPass]
|
||||
|
||||
@@ -347,43 +157,50 @@ proc evalNim(nodes: PNode, module: PSym) =
|
||||
carryPasses(nodes, module, evalPasses)
|
||||
|
||||
proc commandEval(exp: string) =
|
||||
if SystemModule == nil:
|
||||
InteractivePasses()
|
||||
if systemModule == nil:
|
||||
interactivePasses()
|
||||
compileSystemModule()
|
||||
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
||||
evalNim(echoExp.parseString, makeStdinModule())
|
||||
|
||||
proc CommandPretty =
|
||||
proc commandPrettyOld =
|
||||
var projectFile = addFileExt(mainCommandArg(), NimExt)
|
||||
var module = parseFile(projectFile.fileInfoIdx)
|
||||
if module != nil:
|
||||
if module != nil:
|
||||
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
|
||||
|
||||
proc CommandScan =
|
||||
var f = addFileExt(mainCommandArg(), nimExt)
|
||||
var stream = LLStreamOpen(f, fmRead)
|
||||
if stream != nil:
|
||||
var
|
||||
|
||||
proc commandPretty =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
semanticPasses()
|
||||
registerPass(prettyPass)
|
||||
compileProject()
|
||||
pretty.overwriteFiles()
|
||||
|
||||
proc commandScan =
|
||||
var f = addFileExt(mainCommandArg(), NimExt)
|
||||
var stream = llStreamOpen(f, fmRead)
|
||||
if stream != nil:
|
||||
var
|
||||
L: TLexer
|
||||
tok: TToken
|
||||
initToken(tok)
|
||||
openLexer(L, f, stream)
|
||||
while true:
|
||||
while true:
|
||||
rawGetTok(L, tok)
|
||||
PrintTok(tok)
|
||||
if tok.tokType == tkEof: break
|
||||
CloseLexer(L)
|
||||
else:
|
||||
printTok(tok)
|
||||
if tok.tokType == tkEof: break
|
||||
closeLexer(L)
|
||||
else:
|
||||
rawMessage(errCannotOpenFile, f)
|
||||
|
||||
proc CommandSuggest =
|
||||
|
||||
proc commandSuggest =
|
||||
if isServing:
|
||||
# XXX: hacky work-around ahead
|
||||
# Currently, it's possible to issue a idetools command, before
|
||||
# issuing the first compile command. This will leave the compiler
|
||||
# cache in a state where "no recompilation is necessary", but the
|
||||
# cgen pass was never executed at all.
|
||||
CommandCompileToC()
|
||||
commandCompileToC()
|
||||
if gDirtyBufferIdx != 0:
|
||||
discard compileModule(gDirtyBufferIdx, {sfDirty})
|
||||
resetModule(gDirtyBufferIdx)
|
||||
@@ -393,26 +210,30 @@ proc CommandSuggest =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
semanticPasses()
|
||||
rodPass()
|
||||
compileProject()
|
||||
# XXX: this handles the case when the dirty buffer is the main file,
|
||||
# but doesn't handle the case when it's imported module
|
||||
var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
|
||||
else: gProjectMainIdx
|
||||
compileProject(projFile)
|
||||
|
||||
proc wantMainModule =
|
||||
if gProjectFull.len == 0:
|
||||
if optMainModule.len == 0:
|
||||
Fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||
else:
|
||||
gProjectName = optMainModule
|
||||
gProjectFull = gProjectPath / gProjectName
|
||||
|
||||
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
|
||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||
|
||||
proc requireMainModuleOption =
|
||||
if optMainModule.len == 0:
|
||||
Fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
|
||||
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
|
||||
else:
|
||||
gProjectName = optMainModule
|
||||
gProjectFull = gProjectPath / gProjectName
|
||||
|
||||
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
|
||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||
|
||||
proc resetMemory =
|
||||
resetCompilationLists()
|
||||
@@ -425,7 +246,7 @@ proc resetMemory =
|
||||
for i in low(buckets)..high(buckets):
|
||||
buckets[i] = nil
|
||||
idAnon = nil
|
||||
|
||||
|
||||
# XXX: clean these global vars
|
||||
# ccgstmts.gBreakpoints
|
||||
# ccgthreadvars.nimtv
|
||||
@@ -441,7 +262,7 @@ proc resetMemory =
|
||||
# rodread.rodcompilerProcs
|
||||
# rodread.gTypeTable
|
||||
# rodread.gMods
|
||||
|
||||
|
||||
# !! ropes.cache
|
||||
# semthreads.computed?
|
||||
#
|
||||
@@ -465,10 +286,10 @@ const
|
||||
SimiluateCaasMemReset = false
|
||||
PrintRopeCacheStats = false
|
||||
|
||||
proc MainCommand =
|
||||
proc mainCommand* =
|
||||
when SimiluateCaasMemReset:
|
||||
gGlobalOptions.incl(optCaasEnabled)
|
||||
|
||||
|
||||
# In "nimrod serve" scenario, each command must reset the registered passes
|
||||
clearPasses()
|
||||
gLastCmdTime = epochTime()
|
||||
@@ -476,90 +297,96 @@ proc MainCommand =
|
||||
if gProjectFull.len != 0:
|
||||
# current path is always looked first for modules
|
||||
prependStr(searchPaths, gProjectPath)
|
||||
setID(100)
|
||||
setId(100)
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
case command.normalize
|
||||
of "c", "cc", "compile", "compiletoc":
|
||||
of "c", "cc", "compile", "compiletoc":
|
||||
# compile means compileToC currently
|
||||
gCmd = cmdCompileToC
|
||||
wantMainModule()
|
||||
CommandCompileToC()
|
||||
commandCompileToC()
|
||||
of "cpp", "compiletocpp":
|
||||
extccomp.cExt = ".cpp"
|
||||
gCmd = cmdCompileToCpp
|
||||
if cCompiler == ccGcc: setCC("gpp")
|
||||
wantMainModule()
|
||||
DefineSymbol("cpp")
|
||||
CommandCompileToC()
|
||||
defineSymbol("cpp")
|
||||
commandCompileToC()
|
||||
of "objc", "compiletooc":
|
||||
extccomp.cExt = ".m"
|
||||
gCmd = cmdCompileToOC
|
||||
wantMainModule()
|
||||
DefineSymbol("objc")
|
||||
CommandCompileToC()
|
||||
defineSymbol("objc")
|
||||
commandCompileToC()
|
||||
of "run":
|
||||
gCmd = cmdRun
|
||||
wantMainModule()
|
||||
when hasTinyCBackend:
|
||||
extccomp.setCC("tcc")
|
||||
CommandCompileToC()
|
||||
else:
|
||||
commandCompileToC()
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
of "js", "compiletojs":
|
||||
of "js", "compiletojs":
|
||||
gCmd = cmdCompileToJS
|
||||
wantMainModule()
|
||||
CommandCompileToJS()
|
||||
of "compiletollvm":
|
||||
commandCompileToJS()
|
||||
of "compiletollvm":
|
||||
gCmd = cmdCompileToLLVM
|
||||
wantMainModule()
|
||||
when has_LLVM_Backend:
|
||||
when hasLLVM_Backend:
|
||||
CommandCompileToLLVM()
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
of "pretty":
|
||||
gCmd = cmdPretty
|
||||
wantMainModule()
|
||||
CommandPretty()
|
||||
commandPretty()
|
||||
of "doc":
|
||||
gCmd = cmdDoc
|
||||
LoadConfigs(DocConfig)
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
CommandDoc()
|
||||
commandDoc()
|
||||
of "doc2":
|
||||
gCmd = cmdDoc
|
||||
LoadConfigs(DocConfig)
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
DefineSymbol("nimdoc")
|
||||
CommandDoc2()
|
||||
of "rst2html":
|
||||
defineSymbol("nimdoc")
|
||||
commandDoc2()
|
||||
of "rst2html":
|
||||
gCmd = cmdRst2html
|
||||
LoadConfigs(DocConfig)
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
CommandRst2Html()
|
||||
of "rst2tex":
|
||||
commandRst2Html()
|
||||
of "rst2tex":
|
||||
gCmd = cmdRst2tex
|
||||
LoadConfigs(DocTexConfig)
|
||||
loadConfigs(DocTexConfig)
|
||||
wantMainModule()
|
||||
CommandRst2TeX()
|
||||
commandRst2TeX()
|
||||
of "jsondoc":
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
defineSymbol("nimdoc")
|
||||
commandJSON()
|
||||
of "buildindex":
|
||||
gCmd = cmdDoc
|
||||
LoadConfigs(DocConfig)
|
||||
CommandBuildIndex()
|
||||
of "gendepend":
|
||||
loadConfigs(DocConfig)
|
||||
commandBuildIndex()
|
||||
of "gendepend":
|
||||
gCmd = cmdGenDepend
|
||||
wantMainModule()
|
||||
CommandGenDepend()
|
||||
commandGenDepend()
|
||||
of "dump":
|
||||
gcmd = cmdDump
|
||||
if getconfigvar("dump.format") == "json":
|
||||
gCmd = cmdDump
|
||||
if getConfigVar("dump.format") == "json":
|
||||
requireMainModuleOption()
|
||||
|
||||
var definedSymbols = newJArray()
|
||||
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
|
||||
|
||||
var libpaths = newJArray()
|
||||
for dir in itersearchpath(searchpaths): libpaths.elems.add(%dir)
|
||||
for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir)
|
||||
|
||||
var dumpdata = % [
|
||||
(key: "version", val: %VersionAsString),
|
||||
@@ -568,29 +395,29 @@ proc MainCommand =
|
||||
(key: "lib_paths", val: libpaths)
|
||||
]
|
||||
|
||||
outWriteLn($dumpdata)
|
||||
outWriteln($dumpdata)
|
||||
else:
|
||||
outWriteLn("-- list of currently defined symbols --")
|
||||
for s in definedSymbolNames(): outWriteLn(s)
|
||||
outWriteLn("-- end of list --")
|
||||
outWriteln("-- list of currently defined symbols --")
|
||||
for s in definedSymbolNames(): outWriteln(s)
|
||||
outWriteln("-- end of list --")
|
||||
|
||||
for it in iterSearchPath(searchpaths): msgWriteLn(it)
|
||||
for it in iterSearchPath(searchPaths): msgWriteln(it)
|
||||
of "check":
|
||||
gCmd = cmdCheck
|
||||
wantMainModule()
|
||||
CommandCheck()
|
||||
of "parse":
|
||||
commandCheck()
|
||||
of "parse":
|
||||
gCmd = cmdParse
|
||||
wantMainModule()
|
||||
discard parseFile(gProjectMainIdx)
|
||||
of "scan":
|
||||
of "scan":
|
||||
gCmd = cmdScan
|
||||
wantMainModule()
|
||||
CommandScan()
|
||||
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
||||
of "i":
|
||||
commandScan()
|
||||
msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
||||
of "i":
|
||||
gCmd = cmdInteractive
|
||||
CommandInteractive()
|
||||
commandInteractive()
|
||||
of "e":
|
||||
# XXX: temporary command for easier testing
|
||||
commandEval(mainCommandArg())
|
||||
@@ -602,16 +429,18 @@ proc MainCommand =
|
||||
commandEval(gEvalExpr)
|
||||
else:
|
||||
wantMainModule()
|
||||
CommandSuggest()
|
||||
commandSuggest()
|
||||
of "serve":
|
||||
isServing = true
|
||||
gGlobalOptions.incl(optCaasEnabled)
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
serve(MainCommand)
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
serve(mainCommand)
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
|
||||
if msgs.gErrorCounter == 0 and gCmd notin {cmdInterpret, cmdRun, cmdDump}:
|
||||
|
||||
if (msgs.gErrorCounter == 0 and
|
||||
gCmd notin {cmdInterpret, cmdRun, cmdDump} and
|
||||
gVerbosity > 0):
|
||||
rawMessage(hintSuccessX, [$gLinesCompiled,
|
||||
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
|
||||
formatSize(getTotalMem())])
|
||||
@@ -621,7 +450,8 @@ proc MainCommand =
|
||||
echo " tries : ", gCacheTries
|
||||
echo " misses: ", gCacheMisses
|
||||
echo " int tries: ", gCacheIntTries
|
||||
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3)
|
||||
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
|
||||
ffDecimal, 3)
|
||||
|
||||
when SimiluateCaasMemReset:
|
||||
resetMemory()
|
||||
|
||||
201
compiler/modules.nim
Normal file
201
compiler/modules.nim
Normal file
@@ -0,0 +1,201 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## implements the module handling
|
||||
|
||||
import
|
||||
ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
|
||||
idents, os, lexer, idgen, passes, syntaxes
|
||||
|
||||
type
|
||||
TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
|
||||
TCrcStatus* = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged
|
||||
|
||||
TModuleInMemory* = object
|
||||
compiledAt*: float
|
||||
crc*: TCrc32
|
||||
deps*: seq[int32] ## XXX: slurped files are currently not tracked
|
||||
needsRecompile*: TNeedRecompile
|
||||
crcStatus*: TCrcStatus
|
||||
|
||||
var
|
||||
gCompiledModules: seq[PSym] = @[]
|
||||
gMemCacheData*: seq[TModuleInMemory] = @[]
|
||||
## XXX: we should implement recycling of file IDs
|
||||
## if the user keeps renaming modules, the file IDs will keep growing
|
||||
|
||||
proc getModule(fileIdx: int32): PSym =
|
||||
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
||||
result = gCompiledModules[fileIdx]
|
||||
|
||||
template compiledAt(x: PSym): expr =
|
||||
gMemCacheData[x.position].compiledAt
|
||||
|
||||
template crc(x: PSym): expr =
|
||||
gMemCacheData[x.position].crc
|
||||
|
||||
proc crcChanged(fileIdx: int32): bool =
|
||||
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
|
||||
|
||||
template updateStatus =
|
||||
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
|
||||
else: crcNotChanged
|
||||
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result
|
||||
|
||||
case gMemCacheData[fileIdx].crcStatus:
|
||||
of crcHasChanged:
|
||||
result = true
|
||||
of crcNotChanged:
|
||||
result = false
|
||||
of crcCached:
|
||||
let newCrc = crcFromFile(fileIdx.toFilename)
|
||||
result = newCrc != gMemCacheData[fileIdx].crc
|
||||
gMemCacheData[fileIdx].crc = newCrc
|
||||
updateStatus()
|
||||
of crcNotTaken:
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
result = true
|
||||
updateStatus()
|
||||
|
||||
proc doCRC(fileIdx: int32) =
|
||||
if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
|
||||
# echo "FIRST CRC: ", fileIdx.ToFilename
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
|
||||
proc addDep(x: PSym, dep: int32) =
|
||||
growCache gMemCacheData, dep
|
||||
gMemCacheData[x.position].deps.safeAdd(dep)
|
||||
|
||||
proc resetModule*(fileIdx: int32) =
|
||||
# echo "HARD RESETTING ", fileIdx.toFilename
|
||||
gMemCacheData[fileIdx].needsRecompile = Yes
|
||||
gCompiledModules[fileIdx] = nil
|
||||
cgendata.gModules[fileIdx] = nil
|
||||
resetSourceMap(fileIdx)
|
||||
|
||||
proc resetAllModules* =
|
||||
for i in 0..gCompiledModules.high:
|
||||
if gCompiledModules[i] != nil:
|
||||
resetModule(i.int32)
|
||||
resetPackageCache()
|
||||
# for m in cgenModules(): echo "CGEN MODULE FOUND"
|
||||
|
||||
proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
||||
template markDirty =
|
||||
resetModule(fileIdx)
|
||||
return Yes
|
||||
|
||||
if gMemCacheData[fileIdx].needsRecompile != Maybe:
|
||||
return gMemCacheData[fileIdx].needsRecompile
|
||||
|
||||
if optForceFullMake in gGlobalOptions or
|
||||
crcChanged(fileIdx):
|
||||
markDirty
|
||||
|
||||
if gMemCacheData[fileIdx].deps != nil:
|
||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
||||
for dep in gMemCacheData[fileIdx].deps:
|
||||
let d = checkDepMem(dep)
|
||||
if d in {Yes, Recompiled}:
|
||||
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
|
||||
markDirty
|
||||
|
||||
gMemCacheData[fileIdx].needsRecompile = No
|
||||
return No
|
||||
|
||||
proc newModule(fileIdx: int32): PSym =
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
new(result)
|
||||
result.id = - 1 # for better error checking
|
||||
result.kind = skModule
|
||||
let filename = fileIdx.toFilename
|
||||
result.name = getIdent(splitFile(filename).name)
|
||||
if not isNimrodIdentifier(result.name.s):
|
||||
rawMessage(errInvalidModuleName, result.name.s)
|
||||
|
||||
result.info = newLineInfo(fileIdx, 1, 1)
|
||||
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
|
||||
result.info)
|
||||
result.position = fileIdx
|
||||
|
||||
growCache gMemCacheData, fileIdx
|
||||
growCache gCompiledModules, fileIdx
|
||||
gCompiledModules[result.position] = result
|
||||
|
||||
incl(result.flags, sfUsed)
|
||||
initStrTable(result.tab)
|
||||
strTableAdd(result.tab, result) # a module knows itself
|
||||
|
||||
proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
|
||||
result = getModule(fileIdx)
|
||||
if result == nil:
|
||||
growCache gMemCacheData, fileIdx
|
||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
||||
result = newModule(fileIdx)
|
||||
#var rd = handleSymbolFile(result)
|
||||
var rd: PRodReader
|
||||
result.flags = result.flags + flags
|
||||
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
|
||||
rd = handleSymbolFile(result)
|
||||
if result.id < 0:
|
||||
internalError("handleSymbolFile should have set the module\'s ID")
|
||||
return
|
||||
else:
|
||||
result.id = getID()
|
||||
processModule(result, nil, rd)
|
||||
if optCaasEnabled in gGlobalOptions:
|
||||
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
|
||||
gMemCacheData[fileIdx].needsRecompile = Recompiled
|
||||
doCRC fileIdx
|
||||
else:
|
||||
if checkDepMem(fileIdx) == Yes:
|
||||
result = compileModule(fileIdx, flags)
|
||||
else:
|
||||
result = gCompiledModules[fileIdx]
|
||||
|
||||
proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
|
||||
# this is called by the semantic checking phase
|
||||
result = compileModule(fileIdx, {})
|
||||
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
|
||||
if sfSystemModule in result.flags:
|
||||
localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
|
||||
proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
|
||||
result = syntaxes.parseFile(fileIdx)
|
||||
if optCaasEnabled in gGlobalOptions:
|
||||
growCache gMemCacheData, fileIdx
|
||||
addDep(s, fileIdx)
|
||||
doCRC(fileIdx)
|
||||
|
||||
proc `==^`(a, b: string): bool =
|
||||
try:
|
||||
result = sameFile(a, b)
|
||||
except EOS:
|
||||
result = false
|
||||
|
||||
proc compileSystemModule* =
|
||||
if magicsys.systemModule == nil:
|
||||
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
||||
discard compileModule(systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc compileProject*(projectFile = gProjectMainIdx) =
|
||||
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
||||
if projectFile == systemFileIdx:
|
||||
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
compileSystemModule()
|
||||
discard compileModule(projectFile, {sfMainModule})
|
||||
|
||||
var stdinModule: PSym
|
||||
proc makeStdinModule*(): PSym =
|
||||
if stdinModule == nil:
|
||||
stdinModule = newModule(fileInfoIdx"stdin")
|
||||
stdinModule.id = getID()
|
||||
result = stdinModule
|
||||
@@ -8,7 +8,10 @@
|
||||
#
|
||||
|
||||
import
|
||||
options, strutils, os, tables, sockets, ropes, platform
|
||||
options, strutils, os, tables, ropes, platform
|
||||
|
||||
when useCaas:
|
||||
import sockets
|
||||
|
||||
type
|
||||
TMsgKind* = enum
|
||||
@@ -64,7 +67,7 @@ type
|
||||
errAmbiguousCallXYZ, errWrongNumberOfArguments,
|
||||
errXCannotBePassedToProcVar,
|
||||
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
|
||||
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue,
|
||||
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
||||
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
|
||||
errInvalidOrderInArrayConstructor,
|
||||
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
|
||||
@@ -85,12 +88,16 @@ type
|
||||
errTemplateInstantiationTooNested, errInstantiationFrom,
|
||||
errInvalidIndexValueForTuple, errCommandExpectsFilename,
|
||||
errMainModuleMustBeSpecified,
|
||||
errXExpected,
|
||||
errXExpected,
|
||||
errTIsNotAConcreteType,
|
||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
|
||||
|
||||
errXExpectsTwoArguments,
|
||||
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
||||
errMacroBodyDependsOnGenericTypes,
|
||||
errDestructorNotGenericEnough,
|
||||
errInlineIteratorsAsProcParams,
|
||||
errXExpectsTwoArguments,
|
||||
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
|
||||
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
|
||||
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
|
||||
@@ -98,6 +105,10 @@ type
|
||||
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
|
||||
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
|
||||
errXCannotBeClosure, errXMustBeCompileTime,
|
||||
errCannotInferTypeOfTheLiteral,
|
||||
errCannotInferReturnType,
|
||||
errGenericLambdaNotAllowed,
|
||||
errCompilerDoesntSupportTarget,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
@@ -106,11 +117,13 @@ type
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored,
|
||||
warnNilStatement, warnAnalysisLoophole,
|
||||
warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure,
|
||||
warnEachIdentIsTuple, warnShadowIdent, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintPattern,
|
||||
hintUser
|
||||
|
||||
@@ -157,7 +170,7 @@ const
|
||||
errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
|
||||
errCannotReturnExpr: "current routine cannot return an expression",
|
||||
errAttemptToRedefine: "redefinition of \'$1\'",
|
||||
errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\' or \'raise\'",
|
||||
errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
|
||||
errStmtExpected: "statement expected",
|
||||
errInvalidLabel: "\'$1\' is no label",
|
||||
errInvalidCmdLineOption: "invalid command line option: \'$1\'",
|
||||
@@ -189,7 +202,7 @@ const
|
||||
errXExpectsArrayType: "\'$1\' expects an array type",
|
||||
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
|
||||
errExprXAmbiguous: "expression '$1' ambiguous in this context",
|
||||
errConstantDivisionByZero: "constant division by zero",
|
||||
errConstantDivisionByZero: "division by zero",
|
||||
errOrdinalTypeExpected: "ordinal type expected",
|
||||
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
|
||||
errOverOrUnderflow: "over- or underflow",
|
||||
@@ -256,7 +269,7 @@ const
|
||||
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
|
||||
errImplOfXexpected: "implementation of \'$1\' expected",
|
||||
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
|
||||
errDiscardValue: "value returned by statement has to be discarded",
|
||||
errDiscardValueX: "value of type '$1' has to be discarded",
|
||||
errInvalidDiscard: "statement returns no value that can be discarded",
|
||||
errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
|
||||
errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
|
||||
@@ -305,6 +318,7 @@ const
|
||||
errCommandExpectsFilename: "command expects a filename argument",
|
||||
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
|
||||
errXExpected: "\'$1\' expected",
|
||||
errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
|
||||
errInvalidSectionStart: "invalid section start",
|
||||
errGridTableNotImplemented: "grid table is not implemented",
|
||||
errGeneralParseError: "general parse error",
|
||||
@@ -314,6 +328,14 @@ const
|
||||
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
||||
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
||||
errInstantiateXExplicitely: "instantiate '$1' explicitely",
|
||||
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
|
||||
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
||||
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
|
||||
"because the parameter '$1' has a generic type",
|
||||
errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
|
||||
"A destructor must be associated will all instantiations of a generic type",
|
||||
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
|
||||
"templates, macros and other inline iterators",
|
||||
errXExpectsTwoArguments: "\'$1\' expects two arguments",
|
||||
errXExpectsObjectTypes: "\'$1\' expects object types",
|
||||
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
|
||||
@@ -335,6 +357,12 @@ const
|
||||
errIllegalCaptureX: "illegal capture '$1'",
|
||||
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
||||
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
|
||||
errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
|
||||
errCannotInferReturnType: "cannot infer the return type of the proc",
|
||||
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
||||
"it is used as an operand to another routine and the types " &
|
||||
"of the generic paramers can be infered from the expected signature.",
|
||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
||||
@@ -355,6 +383,13 @@ const
|
||||
warnImplicitClosure: "implicit closure convention: '$1' [ImplicitClosure]",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]",
|
||||
warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]",
|
||||
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
|
||||
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
|
||||
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
|
||||
warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.",
|
||||
warnUninit: "'$1' might not have been initialized [Uninit]",
|
||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||
warnUser: "$1 [User]",
|
||||
hintSuccess: "operation successful [Success]",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||
@@ -374,14 +409,16 @@ const
|
||||
hintUser: "$1 [User]"]
|
||||
|
||||
const
|
||||
WarningsToStr*: array[0..19, string] = ["CannotOpenFile", "OctalEscape",
|
||||
WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported",
|
||||
"CommentXIgnored", "NilStmt",
|
||||
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", "User"]
|
||||
"ImplicitClosure", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "User"]
|
||||
|
||||
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
@@ -406,7 +443,7 @@ type
|
||||
TFileInfo*{.final.} = object
|
||||
fullPath*: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: PRope # cached quoted short name for codegen
|
||||
# purpoes
|
||||
|
||||
@@ -423,9 +460,16 @@ type
|
||||
# only 8 bytes.
|
||||
line*, col*: int16
|
||||
fileIndex*: int32
|
||||
|
||||
|
||||
TErrorOutput* = enum
|
||||
eStdOut
|
||||
eStdErr
|
||||
eInMemory
|
||||
|
||||
TErrorOutputs* = set[TErrorOutput]
|
||||
|
||||
ERecoverableError* = object of EInvalidValue
|
||||
ESuggestDone* = object of EBase
|
||||
ESuggestDone* = object of E_Base
|
||||
|
||||
const
|
||||
InvalidFileIDX* = int32(-1)
|
||||
@@ -433,9 +477,9 @@ const
|
||||
var
|
||||
filenameToIndexTbl = initTable[string, int32]()
|
||||
fileInfos*: seq[TFileInfo] = @[]
|
||||
SystemFileIdx*: int32
|
||||
systemFileIdx*: int32
|
||||
|
||||
proc toCChar*(c: Char): string =
|
||||
proc toCChar*(c: char): string =
|
||||
case c
|
||||
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
|
||||
of '\'', '\"', '\\': result = '\\' & c
|
||||
@@ -454,7 +498,7 @@ proc makeCString*(s: string): PRope =
|
||||
add(res, '\"')
|
||||
add(res, tnl)
|
||||
app(result, toRope(res)) # reset:
|
||||
setlen(res, 1)
|
||||
setLen(res, 1)
|
||||
res[0] = '\"'
|
||||
add(res, toCChar(s[i]))
|
||||
add(res, '\"')
|
||||
@@ -466,7 +510,9 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||
#shallow(result.fullPath)
|
||||
result.projPath = projPath
|
||||
#shallow(result.projPath)
|
||||
result.quotedName = projPath.extractFilename.makeCString
|
||||
let fileName = projPath.extractFilename
|
||||
result.shortName = fileName.changeFileExt("")
|
||||
result.quotedName = fileName.makeCString
|
||||
if optEmbedOrigSrc in gGlobalOptions or true:
|
||||
result.lines = @[]
|
||||
|
||||
@@ -512,22 +558,46 @@ proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
proc sourceLine*(i: TLineInfo): PRope
|
||||
|
||||
var
|
||||
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent}
|
||||
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
|
||||
{warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex, warnGcUnsafe}
|
||||
gErrorCounter*: int = 0 # counts the number of errors
|
||||
gHintCounter*: int = 0
|
||||
gWarnCounter*: int = 0
|
||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||
gSilence*: int # == 0 if we produce any output at all
|
||||
stdoutSocket*: TSocket
|
||||
|
||||
proc SuggestWriteln*(s: string) =
|
||||
if gSilence == 0:
|
||||
if isNil(stdoutSocket): Writeln(stdout, s)
|
||||
else:
|
||||
Writeln(stdout, s)
|
||||
stdoutSocket.send(s & "\c\L")
|
||||
when useCaas:
|
||||
var stdoutSocket*: TSocket
|
||||
|
||||
proc SuggestQuit*() =
|
||||
proc unknownLineInfo*(): TLineInfo =
|
||||
result.line = int16(-1)
|
||||
result.col = int16(-1)
|
||||
result.fileIndex = -1
|
||||
|
||||
var
|
||||
msgContext: seq[TLineInfo] = @[]
|
||||
lastError = unknownLineInfo()
|
||||
bufferedMsgs*: seq[string]
|
||||
|
||||
errorOutputs* = {eStdOut, eStdErr}
|
||||
|
||||
proc clearBufferedMsgs* =
|
||||
bufferedMsgs = nil
|
||||
|
||||
proc suggestWriteln*(s: string) =
|
||||
if eStdOut in errorOutputs:
|
||||
when useCaas:
|
||||
if isNil(stdoutSocket): writeln(stdout, s)
|
||||
else:
|
||||
writeln(stdout, s)
|
||||
stdoutSocket.send(s & "\c\L")
|
||||
else:
|
||||
writeln(stdout, s)
|
||||
|
||||
if eInMemory in errorOutputs:
|
||||
bufferedMsgs.safeAdd(s)
|
||||
|
||||
proc suggestQuit*() =
|
||||
if not isServing:
|
||||
quit(0)
|
||||
elif isWorkingWithDirtyBuffer:
|
||||
@@ -548,14 +618,6 @@ const
|
||||
RawWarningFormat* = "Warning: $1"
|
||||
RawHintFormat* = "Hint: $1"
|
||||
|
||||
proc UnknownLineInfo*(): TLineInfo =
|
||||
result.line = int16(-1)
|
||||
result.col = int16(-1)
|
||||
result.fileIndex = -1
|
||||
|
||||
var
|
||||
msgContext: seq[TLineInfo] = @[]
|
||||
|
||||
proc getInfoContextLen*(): int = return msgContext.len
|
||||
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
||||
|
||||
@@ -563,12 +625,12 @@ proc pushInfoContext*(info: TLineInfo) =
|
||||
msgContext.add(info)
|
||||
|
||||
proc popInfoContext*() =
|
||||
setlen(msgContext, len(msgContext) - 1)
|
||||
setLen(msgContext, len(msgContext) - 1)
|
||||
|
||||
proc getInfoContext*(index: int): TLineInfo =
|
||||
let L = msgContext.len
|
||||
let i = if index < 0: L + index else: index
|
||||
if i >=% L: result = UnknownLineInfo()
|
||||
if i >=% L: result = unknownLineInfo()
|
||||
else: result = msgContext[i]
|
||||
|
||||
proc toFilename*(fileIdx: int32): string =
|
||||
@@ -605,6 +667,8 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
|
||||
proc toFileLineCol*(info: TLineInfo): string {.inline.} =
|
||||
result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
|
||||
|
||||
template `$`*(info: TLineInfo): expr = toFileLineCol(info)
|
||||
|
||||
proc `??`* (info: TLineInfo, filename: string): bool =
|
||||
# only for debugging purposes
|
||||
result = filename in info.toFilename
|
||||
@@ -618,24 +682,28 @@ proc addCheckpoint*(info: TLineInfo) =
|
||||
proc addCheckpoint*(filename: string, line: int) =
|
||||
addCheckpoint(newLineInfo(filename, line, - 1))
|
||||
|
||||
proc OutWriteln*(s: string) =
|
||||
proc outWriteln*(s: string) =
|
||||
## Writes to stdout. Always.
|
||||
if gSilence == 0: Writeln(stdout, s)
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
|
||||
proc MsgWriteln*(s: string) =
|
||||
proc msgWriteln*(s: string) =
|
||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||
if gSilence == 0:
|
||||
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
||||
else: Writeln(stdout, s)
|
||||
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
if eStdErr in errorOutputs: writeln(stderr, s)
|
||||
else:
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
|
||||
if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
|
||||
|
||||
proc coordToStr(coord: int): string =
|
||||
if coord == -1: result = "???"
|
||||
else: result = $coord
|
||||
|
||||
proc MsgKindToString*(kind: TMsgKind): string =
|
||||
proc msgKindToString*(kind: TMsgKind): string =
|
||||
# later versions may provide translated error messages
|
||||
result = msgKindToStr[kind]
|
||||
result = MsgKindToStr[kind]
|
||||
|
||||
proc getMessageStr(msg: TMsgKind, arg: string): string =
|
||||
result = msgKindToString(msg) % [arg]
|
||||
@@ -657,70 +725,64 @@ type
|
||||
TErrorHandling = enum doNothing, doAbort, doRaise
|
||||
|
||||
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||
template maybeTrace =
|
||||
if defined(debug) or gVerbosity >= 3:
|
||||
template quit =
|
||||
if defined(debug) or gVerbosity >= 3 or msg == errInternal:
|
||||
writeStackTrace()
|
||||
quit 1
|
||||
|
||||
if msg == errInternal:
|
||||
writeStackTrace() # we always want a stack trace here
|
||||
if msg >= fatalMin and msg <= fatalMax:
|
||||
maybeTrace()
|
||||
quit(1)
|
||||
if msg >= errMin and msg <= errMax:
|
||||
maybeTrace()
|
||||
if msg >= fatalMin and msg <= fatalMax:
|
||||
quit()
|
||||
if msg >= errMin and msg <= errMax:
|
||||
inc(gErrorCounter)
|
||||
options.gExitcode = 1'i8
|
||||
if gErrorCounter >= gErrorMax:
|
||||
quit(1)
|
||||
if gErrorCounter >= gErrorMax:
|
||||
quit()
|
||||
elif eh == doAbort and gCmd != cmdIdeTools:
|
||||
quit(1)
|
||||
quit()
|
||||
elif eh == doRaise:
|
||||
raiseRecoverableError(s)
|
||||
|
||||
proc `==`*(a, b: TLineInfo): bool =
|
||||
proc `==`*(a, b: TLineInfo): bool =
|
||||
result = a.line == b.line and a.fileIndex == b.fileIndex
|
||||
|
||||
proc writeContext(lastinfo: TLineInfo) =
|
||||
var info = lastInfo
|
||||
var info = lastinfo
|
||||
for i in countup(0, len(msgContext) - 1):
|
||||
if msgContext[i] != lastInfo and msgContext[i] != info:
|
||||
MsgWriteln(posContextFormat % [toMsgFilename(msgContext[i]),
|
||||
if msgContext[i] != lastinfo and msgContext[i] != info:
|
||||
msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col),
|
||||
getMessageStr(errInstantiationFrom, "")])
|
||||
info = msgContext[i]
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
|
||||
proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
|
||||
var frmt: string
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
writeContext(unknownLineInfo())
|
||||
frmt = rawErrorFormat
|
||||
frmt = RawErrorFormat
|
||||
of warnMin..warnMax:
|
||||
if optWarns notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
writeContext(unknownLineInfo())
|
||||
frmt = rawWarningFormat
|
||||
frmt = RawWarningFormat
|
||||
inc(gWarnCounter)
|
||||
of hintMin..hintMax:
|
||||
if optHints notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
frmt = rawHintFormat
|
||||
frmt = RawHintFormat
|
||||
inc(gHintCounter)
|
||||
let s = `%`(frmt, `%`(msgKindToString(msg), args))
|
||||
MsgWriteln(s)
|
||||
msgWriteln(s)
|
||||
handleError(msg, doAbort, s)
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||
rawMessage(msg, [arg])
|
||||
|
||||
var
|
||||
lastError = UnknownLineInfo()
|
||||
|
||||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
const indent = " "
|
||||
MsgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
MsgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
||||
|
||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling) =
|
||||
@@ -729,7 +791,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
writeContext(info)
|
||||
frmt = posErrorFormat
|
||||
frmt = PosErrorFormat
|
||||
# we try to filter error messages so that not two error message
|
||||
# in the same file and line are produced:
|
||||
#ignoreMsg = lastError == info and eh != doAbort
|
||||
@@ -737,51 +799,54 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
of warnMin..warnMax:
|
||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||
if not ignoreMsg: writeContext(info)
|
||||
frmt = posWarningFormat
|
||||
frmt = PosWarningFormat
|
||||
inc(gWarnCounter)
|
||||
of hintMin..hintMax:
|
||||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||
frmt = posHintFormat
|
||||
frmt = PosHintFormat
|
||||
inc(gHintCounter)
|
||||
let s = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col), getMessageStr(msg, arg)]
|
||||
if not ignoreMsg:
|
||||
MsgWriteln(s)
|
||||
msgWriteln(s)
|
||||
if optPrintSurroundingSrc and msg in errMin..errMax:
|
||||
info.writeSurroundingSrc
|
||||
handleError(msg, eh, s)
|
||||
|
||||
proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doAbort)
|
||||
|
||||
proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doRaise)
|
||||
|
||||
proc GlobalError*(info: TLineInfo, arg: string) =
|
||||
proc globalError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doRaise)
|
||||
|
||||
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
|
||||
proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc localError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doNothing)
|
||||
|
||||
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
|
||||
proc InternalError*(info: TLineInfo, errMsg: string) =
|
||||
proc internalError*(info: TLineInfo, errMsg: string) =
|
||||
if gCmd == cmdIdeTools: return
|
||||
writeContext(info)
|
||||
liMessage(info, errInternal, errMsg, doAbort)
|
||||
|
||||
proc InternalError*(errMsg: string) =
|
||||
proc internalError*(errMsg: string) =
|
||||
if gCmd == cmdIdeTools: return
|
||||
writeContext(UnknownLineInfo())
|
||||
writeContext(unknownLineInfo())
|
||||
rawMessage(errInternal, errMsg)
|
||||
|
||||
template AssertNotNil*(e: expr): expr =
|
||||
if e == nil: InternalError($InstantiationInfo())
|
||||
template assertNotNil*(e: expr): expr =
|
||||
if e == nil: internalError($instantiationInfo())
|
||||
e
|
||||
|
||||
template InternalAssert*(e: bool): stmt =
|
||||
if not e: InternalError($InstantiationInfo())
|
||||
template internalAssert*(e: bool): stmt =
|
||||
if not e: internalError($instantiationInfo())
|
||||
|
||||
proc addSourceLine*(fileIdx: int32, line: string) =
|
||||
fileInfos[fileIdx].lines.add line.toRope
|
||||
@@ -789,28 +854,28 @@ proc addSourceLine*(fileIdx: int32, line: string) =
|
||||
proc sourceLine*(i: TLineInfo): PRope =
|
||||
if i.fileIndex < 0: return nil
|
||||
|
||||
if not optPreserveOrigSource and
|
||||
fileInfos[i.fileIndex].lines.len == 0:
|
||||
for line in lines(i.toFullPath):
|
||||
addSourceLine i.fileIndex, line.string
|
||||
|
||||
InternalAssert i.fileIndex < fileInfos.len
|
||||
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
|
||||
try:
|
||||
for line in lines(i.toFullPath):
|
||||
addSourceLine i.fileIndex, line.string
|
||||
except EIO:
|
||||
discard
|
||||
internalAssert i.fileIndex < fileInfos.len
|
||||
# can happen if the error points to EOF:
|
||||
if i.line > fileInfos[i.fileIndex].lines.len: return nil
|
||||
|
||||
result = fileInfos[i.fileIndex].lines[i.line-1]
|
||||
|
||||
proc quotedFilename*(i: TLineInfo): PRope =
|
||||
InternalAssert i.fileIndex >= 0
|
||||
internalAssert i.fileIndex >= 0
|
||||
result = fileInfos[i.fileIndex].quotedName
|
||||
|
||||
ropes.ErrorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
|
||||
ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
|
||||
case err
|
||||
of rInvalidFormatStr:
|
||||
internalError("ropes: invalid format string: " & msg)
|
||||
of rTokenTooLong:
|
||||
internalError("ropes: token too long: " & msg)
|
||||
of rCannotOpenFile:
|
||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
|
||||
msg)
|
||||
|
||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ proc parseExpr(L: var TLexer, tok: var TToken): bool =
|
||||
var b = parseAndExpr(L, tok)
|
||||
result = result or b
|
||||
|
||||
proc EvalppIf(L: var TLexer, tok: var TToken): bool =
|
||||
proc evalppIf(L: var TLexer, tok: var TToken): bool =
|
||||
ppGetTok(L, tok) # skip 'if' or 'elif'
|
||||
result = parseExpr(L, tok)
|
||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
||||
@@ -60,7 +60,7 @@ var condStack: seq[bool] = @[]
|
||||
proc doEnd(L: var TLexer, tok: var TToken) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
ppGetTok(L, tok) # skip 'end'
|
||||
setlen(condStack, high(condStack))
|
||||
setLen(condStack, high(condStack))
|
||||
|
||||
type
|
||||
TJumpDest = enum
|
||||
@@ -75,18 +75,18 @@ proc doElse(L: var TLexer, tok: var TToken) =
|
||||
|
||||
proc doElif(L: var TLexer, tok: var TToken) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
var res = EvalppIf(L, tok)
|
||||
var res = evalppIf(L, tok)
|
||||
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
|
||||
else: condStack[high(condStack)] = true
|
||||
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||
var nestedIfs = 0
|
||||
while True:
|
||||
while true:
|
||||
if (tok.ident != nil) and (tok.ident.s == "@"):
|
||||
ppGetTok(L, tok)
|
||||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
Inc(nestedIfs)
|
||||
inc(nestedIfs)
|
||||
of wElse:
|
||||
if (dest == jdElseEndif) and (nestedIfs == 0):
|
||||
doElse(L, tok)
|
||||
@@ -99,21 +99,21 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||
if nestedIfs == 0:
|
||||
doEnd(L, tok)
|
||||
break
|
||||
if nestedIfs > 0: Dec(nestedIfs)
|
||||
if nestedIfs > 0: dec(nestedIfs)
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
ppGetTok(L, tok)
|
||||
elif tok.tokType == tkEof:
|
||||
elif tok.tokType == tkEof:
|
||||
lexMessage(L, errTokenExpected, "@end")
|
||||
else:
|
||||
else:
|
||||
ppGetTok(L, tok)
|
||||
|
||||
proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||
ppGetTok(L, tok) # skip @
|
||||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
setlen(condStack, len(condStack) + 1)
|
||||
var res = EvalppIf(L, tok)
|
||||
setLen(condStack, len(condStack) + 1)
|
||||
var res = evalppIf(L, tok)
|
||||
condStack[high(condStack)] = res
|
||||
if not res: jumpToDirective(L, tok, jdElseEndif)
|
||||
of wElif: doElif(L, tok)
|
||||
@@ -121,7 +121,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||
of wEnd: doEnd(L, tok)
|
||||
of wWrite:
|
||||
ppGetTok(L, tok)
|
||||
msgs.MsgWriteln(tokToStr(tok))
|
||||
msgs.msgWriteln(tokToStr(tok))
|
||||
ppGetTok(L, tok)
|
||||
else:
|
||||
case tok.ident.s.normalize
|
||||
@@ -135,13 +135,13 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
ppGetTok(L, tok)
|
||||
os.putEnv(key, tokToStr(tok) & os.getenv(key))
|
||||
os.putEnv(key, tokToStr(tok) & os.getEnv(key))
|
||||
ppGetTok(L, tok)
|
||||
of "appendenv":
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
ppGetTok(L, tok)
|
||||
os.putEnv(key, os.getenv(key) & tokToStr(tok))
|
||||
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
|
||||
ppGetTok(L, tok)
|
||||
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
|
||||
|
||||
@@ -157,7 +157,7 @@ proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
|
||||
confTok(L, tok) # skip unnecessary prefix
|
||||
var info = getLineInfo(L) # safe for later in case of an error
|
||||
var info = getLineInfo(L, tok) # safe for later in case of an error
|
||||
checkSymbol(L, tok)
|
||||
var s = tokToStr(tok)
|
||||
confTok(L, tok) # skip symbol
|
||||
@@ -176,7 +176,7 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
add(val, tokToStr(tok))
|
||||
confTok(L, tok)
|
||||
if tok.tokType == tkBracketRi: confTok(L, tok)
|
||||
else: lexMessage(L, errTokenExpected, "\']\'")
|
||||
else: lexMessage(L, errTokenExpected, "']'")
|
||||
add(val, ']')
|
||||
if tok.tokType in {tkColon, tkEquals}:
|
||||
if len(val) > 0: add(val, ':')
|
||||
@@ -196,7 +196,7 @@ proc readConfigFile(filename: string) =
|
||||
L: TLexer
|
||||
tok: TToken
|
||||
stream: PLLStream
|
||||
stream = LLStreamOpen(filename, fmRead)
|
||||
stream = llStreamOpen(filename, fmRead)
|
||||
if stream != nil:
|
||||
initToken(tok)
|
||||
openLexer(L, filename, stream)
|
||||
@@ -213,10 +213,13 @@ proc getUserConfigPath(filename: string): string =
|
||||
proc getSystemConfigPath(filename: string): string =
|
||||
# try standard configuration file (installation did not distribute files
|
||||
# the UNIX way)
|
||||
result = joinPath([getPrefixDir(), "config", filename])
|
||||
if not ExistsFile(result): result = "/etc/" & filename
|
||||
let p = getPrefixDir()
|
||||
result = joinPath([p, "config", filename])
|
||||
when defined(unix):
|
||||
if not existsFile(result): result = joinPath([p, "etc", filename])
|
||||
if not existsFile(result): result = "/etc/" & filename
|
||||
|
||||
proc LoadConfigs*(cfg: string) =
|
||||
proc loadConfigs*(cfg: string) =
|
||||
# set default value (can be overwritten):
|
||||
if libpath == "":
|
||||
# choose default libpath:
|
||||
@@ -240,11 +243,6 @@ proc LoadConfigs*(cfg: string) =
|
||||
readConfigFile(pd / cfg)
|
||||
|
||||
if gProjectName.len != 0:
|
||||
var conffile = changeFileExt(gProjectFull, "cfg")
|
||||
if conffile != pd / cfg and existsFile(conffile):
|
||||
readConfigFile(conffile)
|
||||
rawMessage(warnConfigDeprecated, conffile)
|
||||
|
||||
# new project wide config file:
|
||||
readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
|
||||
|
||||
|
||||
33
compiler/nimeval.nim
Normal file
33
compiler/nimeval.nim
Normal file
@@ -0,0 +1,33 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## exposes the Nimrod VM to clients.
|
||||
|
||||
import
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
options, nimconf, lists, sem, semdata, llstream, vm
|
||||
|
||||
proc execute*(program: string) =
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
initDefines()
|
||||
loadConfigs(DefaultConfig)
|
||||
|
||||
initDefines()
|
||||
defineSymbol("nimrodvm")
|
||||
when hasFFI: defineSymbol("nimffi")
|
||||
registerPass(verbosePass)
|
||||
registerPass(semPass)
|
||||
registerPass(vmPass)
|
||||
|
||||
appendStr(searchPaths, options.libpath)
|
||||
compileSystemModule()
|
||||
var m = makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
processModule(m, llStreamOpen(program), nil)
|
||||
@@ -42,7 +42,7 @@ type
|
||||
buf*: cstring
|
||||
bufLen*: int # length of buffer in characters
|
||||
stream*: PLLStream # we read from this stream
|
||||
LineNumber*: int # the current line number
|
||||
lineNumber*: int # the current line number
|
||||
# private data:
|
||||
sentinel*: int
|
||||
lineStart*: int # index of last line start in buffer
|
||||
@@ -54,11 +54,11 @@ proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream,
|
||||
proc closeBaseLexer*(L: var TBaseLexer)
|
||||
proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
|
||||
proc getColNumber*(L: TBaseLexer, pos: int): int
|
||||
proc HandleCR*(L: var TBaseLexer, pos: int): int
|
||||
proc handleCR*(L: var TBaseLexer, pos: int): int
|
||||
# Call this if you scanned over CR in the buffer; it returns the
|
||||
# position to continue the scanning from. `pos` must be the position
|
||||
# of the CR.
|
||||
proc HandleLF*(L: var TBaseLexer, pos: int): int
|
||||
proc handleLF*(L: var TBaseLexer, pos: int): int
|
||||
# Call this if you scanned over LF in the buffer; it returns the the
|
||||
# position to continue the scanning from. `pos` must be the position
|
||||
# of the LF.
|
||||
@@ -69,9 +69,9 @@ const
|
||||
|
||||
proc closeBaseLexer(L: var TBaseLexer) =
|
||||
dealloc(L.buf)
|
||||
LLStreamClose(L.stream)
|
||||
llStreamClose(L.stream)
|
||||
|
||||
proc FillBuffer(L: var TBaseLexer) =
|
||||
proc fillBuffer(L: var TBaseLexer) =
|
||||
var
|
||||
charsRead, toCopy, s: int # all are in characters,
|
||||
# not bytes (in case this
|
||||
@@ -80,12 +80,12 @@ proc FillBuffer(L: var TBaseLexer) =
|
||||
# we know here that pos == L.sentinel, but not if this proc
|
||||
# is called the first time by initBaseLexer()
|
||||
assert(L.sentinel < L.bufLen)
|
||||
toCopy = L.BufLen - L.sentinel - 1
|
||||
toCopy = L.bufLen - L.sentinel - 1
|
||||
assert(toCopy >= 0)
|
||||
if toCopy > 0:
|
||||
MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
|
||||
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
|
||||
# "moveMem" handles overlapping regions
|
||||
charsRead = LLStreamRead(L.stream, addr(L.buf[toCopy]),
|
||||
charsRead = llStreamRead(L.stream, addr(L.buf[toCopy]),
|
||||
(L.sentinel + 1) * chrSize) div chrSize
|
||||
s = toCopy + charsRead
|
||||
if charsRead < L.sentinel + 1:
|
||||
@@ -96,7 +96,7 @@ proc FillBuffer(L: var TBaseLexer) =
|
||||
dec(s) # BUGFIX (valgrind)
|
||||
while true:
|
||||
assert(s < L.bufLen)
|
||||
while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)
|
||||
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
|
||||
if s >= 0:
|
||||
# we found an appropriate character for a sentinel:
|
||||
L.sentinel = s
|
||||
@@ -104,11 +104,11 @@ proc FillBuffer(L: var TBaseLexer) =
|
||||
else:
|
||||
# rather than to give up here because the line is too long,
|
||||
# double the buffer's size and try again:
|
||||
oldBufLen = L.BufLen
|
||||
L.bufLen = L.BufLen * 2
|
||||
oldBufLen = L.bufLen
|
||||
L.bufLen = L.bufLen * 2
|
||||
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
|
||||
assert(L.bufLen - oldBuflen == oldBufLen)
|
||||
charsRead = LLStreamRead(L.stream, addr(L.buf[oldBufLen]),
|
||||
assert(L.bufLen - oldBufLen == oldBufLen)
|
||||
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
|
||||
oldBufLen * chrSize) div chrSize
|
||||
if charsRead < oldBufLen:
|
||||
L.buf[oldBufLen + charsRead] = EndOfFile
|
||||
@@ -126,20 +126,20 @@ proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
|
||||
result = 0
|
||||
L.lineStart = result
|
||||
|
||||
proc HandleCR(L: var TBaseLexer, pos: int): int =
|
||||
proc handleCR(L: var TBaseLexer, pos: int): int =
|
||||
assert(L.buf[pos] == CR)
|
||||
inc(L.linenumber)
|
||||
inc(L.lineNumber)
|
||||
result = fillBaseLexer(L, pos)
|
||||
if L.buf[result] == LF:
|
||||
result = fillBaseLexer(L, result)
|
||||
|
||||
proc HandleLF(L: var TBaseLexer, pos: int): int =
|
||||
proc handleLF(L: var TBaseLexer, pos: int): int =
|
||||
assert(L.buf[pos] == LF)
|
||||
inc(L.linenumber)
|
||||
inc(L.lineNumber)
|
||||
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
|
||||
|
||||
proc skip_UTF_8_BOM(L: var TBaseLexer) =
|
||||
if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
|
||||
proc skipUTF8BOM(L: var TBaseLexer) =
|
||||
if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF':
|
||||
inc(L.bufpos, 3)
|
||||
inc(L.lineStart, 3)
|
||||
|
||||
@@ -150,10 +150,10 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
|
||||
L.buf = cast[cstring](alloc(bufLen * chrSize))
|
||||
L.sentinel = bufLen - 1
|
||||
L.lineStart = 0
|
||||
L.linenumber = 1 # lines start at 1
|
||||
L.lineNumber = 1 # lines start at 1
|
||||
L.stream = inputstream
|
||||
fillBuffer(L)
|
||||
skip_UTF_8_BOM(L)
|
||||
skipUTF8BOM(L)
|
||||
|
||||
proc getColNumber(L: TBaseLexer, pos: int): int =
|
||||
result = abs(pos - L.lineStart)
|
||||
@@ -166,5 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
||||
inc(i)
|
||||
result.add("\n")
|
||||
if marker:
|
||||
result.add(RepeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
|
||||
|
||||
result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
|
||||
|
||||
@@ -1,591 +0,0 @@
|
||||
digraph nimrod {
|
||||
times -> strutils;
|
||||
os -> strutils;
|
||||
os -> times;
|
||||
posix -> times;
|
||||
os -> posix;
|
||||
nhashes -> strutils;
|
||||
nstrtabs -> os;
|
||||
nstrtabs -> nhashes;
|
||||
nstrtabs -> strutils;
|
||||
options -> os;
|
||||
options -> lists;
|
||||
options -> strutils;
|
||||
options -> nstrtabs;
|
||||
msgs -> options;
|
||||
msgs -> strutils;
|
||||
msgs -> os;
|
||||
crc -> strutils;
|
||||
platform -> strutils;
|
||||
ropes -> msgs;
|
||||
ropes -> strutils;
|
||||
ropes -> platform;
|
||||
ropes -> nhashes;
|
||||
ropes -> crc;
|
||||
idents -> nhashes;
|
||||
idents -> strutils;
|
||||
ast -> msgs;
|
||||
ast -> nhashes;
|
||||
ast -> nversion;
|
||||
ast -> options;
|
||||
ast -> strutils;
|
||||
ast -> crc;
|
||||
ast -> ropes;
|
||||
ast -> idents;
|
||||
ast -> lists;
|
||||
astalgo -> ast;
|
||||
astalgo -> nhashes;
|
||||
astalgo -> strutils;
|
||||
astalgo -> options;
|
||||
astalgo -> msgs;
|
||||
astalgo -> ropes;
|
||||
astalgo -> idents;
|
||||
condsyms -> ast;
|
||||
condsyms -> astalgo;
|
||||
condsyms -> msgs;
|
||||
condsyms -> nhashes;
|
||||
condsyms -> platform;
|
||||
condsyms -> strutils;
|
||||
condsyms -> idents;
|
||||
hashes -> strutils;
|
||||
strtabs -> os;
|
||||
strtabs -> hashes;
|
||||
strtabs -> strutils;
|
||||
osproc -> strutils;
|
||||
osproc -> os;
|
||||
osproc -> strtabs;
|
||||
osproc -> streams;
|
||||
osproc -> posix;
|
||||
extccomp -> lists;
|
||||
extccomp -> ropes;
|
||||
extccomp -> os;
|
||||
extccomp -> strutils;
|
||||
extccomp -> osproc;
|
||||
extccomp -> platform;
|
||||
extccomp -> condsyms;
|
||||
extccomp -> options;
|
||||
extccomp -> msgs;
|
||||
wordrecg -> nhashes;
|
||||
wordrecg -> strutils;
|
||||
wordrecg -> idents;
|
||||
commands -> os;
|
||||
commands -> msgs;
|
||||
commands -> options;
|
||||
commands -> nversion;
|
||||
commands -> condsyms;
|
||||
commands -> strutils;
|
||||
commands -> extccomp;
|
||||
commands -> platform;
|
||||
commands -> lists;
|
||||
commands -> wordrecg;
|
||||
llstream -> strutils;
|
||||
lexbase -> llstream;
|
||||
lexbase -> strutils;
|
||||
scanner -> nhashes;
|
||||
scanner -> options;
|
||||
scanner -> msgs;
|
||||
scanner -> strutils;
|
||||
scanner -> platform;
|
||||
scanner -> idents;
|
||||
scanner -> lexbase;
|
||||
scanner -> llstream;
|
||||
scanner -> wordrecg;
|
||||
nimconf -> llstream;
|
||||
nimconf -> nversion;
|
||||
nimconf -> commands;
|
||||
nimconf -> os;
|
||||
nimconf -> strutils;
|
||||
nimconf -> msgs;
|
||||
nimconf -> platform;
|
||||
nimconf -> condsyms;
|
||||
nimconf -> scanner;
|
||||
nimconf -> options;
|
||||
nimconf -> idents;
|
||||
nimconf -> wordrecg;
|
||||
pnimsyn -> llstream;
|
||||
pnimsyn -> scanner;
|
||||
pnimsyn -> idents;
|
||||
pnimsyn -> strutils;
|
||||
pnimsyn -> ast;
|
||||
pnimsyn -> msgs;
|
||||
pbraces -> llstream;
|
||||
pbraces -> scanner;
|
||||
pbraces -> idents;
|
||||
pbraces -> strutils;
|
||||
pbraces -> ast;
|
||||
pbraces -> msgs;
|
||||
pbraces -> pnimsyn;
|
||||
rnimsyn -> scanner;
|
||||
rnimsyn -> options;
|
||||
rnimsyn -> idents;
|
||||
rnimsyn -> strutils;
|
||||
rnimsyn -> ast;
|
||||
rnimsyn -> msgs;
|
||||
rnimsyn -> lists;
|
||||
filters -> llstream;
|
||||
filters -> os;
|
||||
filters -> wordrecg;
|
||||
filters -> idents;
|
||||
filters -> strutils;
|
||||
filters -> ast;
|
||||
filters -> astalgo;
|
||||
filters -> msgs;
|
||||
filters -> options;
|
||||
filters -> rnimsyn;
|
||||
ptmplsyn -> llstream;
|
||||
ptmplsyn -> os;
|
||||
ptmplsyn -> wordrecg;
|
||||
ptmplsyn -> idents;
|
||||
ptmplsyn -> strutils;
|
||||
ptmplsyn -> ast;
|
||||
ptmplsyn -> astalgo;
|
||||
ptmplsyn -> msgs;
|
||||
ptmplsyn -> options;
|
||||
ptmplsyn -> rnimsyn;
|
||||
ptmplsyn -> filters;
|
||||
syntaxes -> strutils;
|
||||
syntaxes -> llstream;
|
||||
syntaxes -> ast;
|
||||
syntaxes -> astalgo;
|
||||
syntaxes -> idents;
|
||||
syntaxes -> scanner;
|
||||
syntaxes -> options;
|
||||
syntaxes -> msgs;
|
||||
syntaxes -> pnimsyn;
|
||||
syntaxes -> pbraces;
|
||||
syntaxes -> ptmplsyn;
|
||||
syntaxes -> filters;
|
||||
syntaxes -> rnimsyn;
|
||||
paslex -> nhashes;
|
||||
paslex -> options;
|
||||
paslex -> msgs;
|
||||
paslex -> strutils;
|
||||
paslex -> platform;
|
||||
paslex -> idents;
|
||||
paslex -> lexbase;
|
||||
paslex -> wordrecg;
|
||||
paslex -> scanner;
|
||||
pasparse -> os;
|
||||
pasparse -> llstream;
|
||||
pasparse -> scanner;
|
||||
pasparse -> paslex;
|
||||
pasparse -> idents;
|
||||
pasparse -> wordrecg;
|
||||
pasparse -> strutils;
|
||||
pasparse -> ast;
|
||||
pasparse -> astalgo;
|
||||
pasparse -> msgs;
|
||||
pasparse -> options;
|
||||
rodread -> os;
|
||||
rodread -> options;
|
||||
rodread -> strutils;
|
||||
rodread -> nversion;
|
||||
rodread -> ast;
|
||||
rodread -> astalgo;
|
||||
rodread -> msgs;
|
||||
rodread -> platform;
|
||||
rodread -> condsyms;
|
||||
rodread -> ropes;
|
||||
rodread -> idents;
|
||||
rodread -> crc;
|
||||
trees -> ast;
|
||||
trees -> astalgo;
|
||||
trees -> scanner;
|
||||
trees -> msgs;
|
||||
trees -> strutils;
|
||||
types -> ast;
|
||||
types -> astalgo;
|
||||
types -> trees;
|
||||
types -> msgs;
|
||||
types -> strutils;
|
||||
types -> platform;
|
||||
magicsys -> ast;
|
||||
magicsys -> astalgo;
|
||||
magicsys -> nhashes;
|
||||
magicsys -> msgs;
|
||||
magicsys -> platform;
|
||||
magicsys -> nversion;
|
||||
magicsys -> times;
|
||||
magicsys -> idents;
|
||||
magicsys -> rodread;
|
||||
nimsets -> ast;
|
||||
nimsets -> astalgo;
|
||||
nimsets -> trees;
|
||||
nimsets -> nversion;
|
||||
nimsets -> msgs;
|
||||
nimsets -> platform;
|
||||
nimsets -> bitsets;
|
||||
nimsets -> types;
|
||||
nimsets -> rnimsyn;
|
||||
passes -> strutils;
|
||||
passes -> lists;
|
||||
passes -> options;
|
||||
passes -> ast;
|
||||
passes -> astalgo;
|
||||
passes -> llstream;
|
||||
passes -> msgs;
|
||||
passes -> platform;
|
||||
passes -> os;
|
||||
passes -> condsyms;
|
||||
passes -> idents;
|
||||
passes -> rnimsyn;
|
||||
passes -> types;
|
||||
passes -> extccomp;
|
||||
passes -> math;
|
||||
passes -> magicsys;
|
||||
passes -> nversion;
|
||||
passes -> nimsets;
|
||||
passes -> syntaxes;
|
||||
passes -> times;
|
||||
passes -> rodread;
|
||||
treetab -> nhashes;
|
||||
treetab -> ast;
|
||||
treetab -> astalgo;
|
||||
treetab -> types;
|
||||
semdata -> strutils;
|
||||
semdata -> lists;
|
||||
semdata -> options;
|
||||
semdata -> scanner;
|
||||
semdata -> ast;
|
||||
semdata -> astalgo;
|
||||
semdata -> trees;
|
||||
semdata -> treetab;
|
||||
semdata -> wordrecg;
|
||||
semdata -> ropes;
|
||||
semdata -> msgs;
|
||||
semdata -> platform;
|
||||
semdata -> os;
|
||||
semdata -> condsyms;
|
||||
semdata -> idents;
|
||||
semdata -> rnimsyn;
|
||||
semdata -> types;
|
||||
semdata -> extccomp;
|
||||
semdata -> math;
|
||||
semdata -> magicsys;
|
||||
semdata -> nversion;
|
||||
semdata -> nimsets;
|
||||
semdata -> pnimsyn;
|
||||
semdata -> times;
|
||||
semdata -> passes;
|
||||
semdata -> rodread;
|
||||
lookups -> ast;
|
||||
lookups -> astalgo;
|
||||
lookups -> idents;
|
||||
lookups -> semdata;
|
||||
lookups -> types;
|
||||
lookups -> msgs;
|
||||
lookups -> options;
|
||||
lookups -> rodread;
|
||||
lookups -> rnimsyn;
|
||||
importer -> strutils;
|
||||
importer -> os;
|
||||
importer -> ast;
|
||||
importer -> astalgo;
|
||||
importer -> msgs;
|
||||
importer -> options;
|
||||
importer -> idents;
|
||||
importer -> rodread;
|
||||
importer -> lookups;
|
||||
importer -> semdata;
|
||||
importer -> passes;
|
||||
rodwrite -> os;
|
||||
rodwrite -> options;
|
||||
rodwrite -> strutils;
|
||||
rodwrite -> nversion;
|
||||
rodwrite -> ast;
|
||||
rodwrite -> astalgo;
|
||||
rodwrite -> msgs;
|
||||
rodwrite -> platform;
|
||||
rodwrite -> condsyms;
|
||||
rodwrite -> ropes;
|
||||
rodwrite -> idents;
|
||||
rodwrite -> crc;
|
||||
rodwrite -> rodread;
|
||||
rodwrite -> passes;
|
||||
rodwrite -> importer;
|
||||
semfold -> strutils;
|
||||
semfold -> lists;
|
||||
semfold -> options;
|
||||
semfold -> ast;
|
||||
semfold -> astalgo;
|
||||
semfold -> trees;
|
||||
semfold -> treetab;
|
||||
semfold -> nimsets;
|
||||
semfold -> times;
|
||||
semfold -> nversion;
|
||||
semfold -> platform;
|
||||
semfold -> math;
|
||||
semfold -> msgs;
|
||||
semfold -> os;
|
||||
semfold -> condsyms;
|
||||
semfold -> idents;
|
||||
semfold -> rnimsyn;
|
||||
semfold -> types;
|
||||
evals -> strutils;
|
||||
evals -> magicsys;
|
||||
evals -> lists;
|
||||
evals -> options;
|
||||
evals -> ast;
|
||||
evals -> astalgo;
|
||||
evals -> trees;
|
||||
evals -> treetab;
|
||||
evals -> nimsets;
|
||||
evals -> msgs;
|
||||
evals -> os;
|
||||
evals -> condsyms;
|
||||
evals -> idents;
|
||||
evals -> rnimsyn;
|
||||
evals -> types;
|
||||
evals -> passes;
|
||||
evals -> semfold;
|
||||
procfind -> ast;
|
||||
procfind -> astalgo;
|
||||
procfind -> msgs;
|
||||
procfind -> semdata;
|
||||
procfind -> types;
|
||||
procfind -> trees;
|
||||
pragmas -> os;
|
||||
pragmas -> platform;
|
||||
pragmas -> condsyms;
|
||||
pragmas -> ast;
|
||||
pragmas -> astalgo;
|
||||
pragmas -> idents;
|
||||
pragmas -> semdata;
|
||||
pragmas -> msgs;
|
||||
pragmas -> rnimsyn;
|
||||
pragmas -> wordrecg;
|
||||
pragmas -> ropes;
|
||||
pragmas -> options;
|
||||
pragmas -> strutils;
|
||||
pragmas -> lists;
|
||||
pragmas -> extccomp;
|
||||
pragmas -> math;
|
||||
pragmas -> magicsys;
|
||||
pragmas -> trees;
|
||||
sem -> strutils;
|
||||
sem -> nhashes;
|
||||
sem -> lists;
|
||||
sem -> options;
|
||||
sem -> scanner;
|
||||
sem -> ast;
|
||||
sem -> astalgo;
|
||||
sem -> trees;
|
||||
sem -> treetab;
|
||||
sem -> wordrecg;
|
||||
sem -> ropes;
|
||||
sem -> msgs;
|
||||
sem -> os;
|
||||
sem -> condsyms;
|
||||
sem -> idents;
|
||||
sem -> rnimsyn;
|
||||
sem -> types;
|
||||
sem -> platform;
|
||||
sem -> math;
|
||||
sem -> magicsys;
|
||||
sem -> pnimsyn;
|
||||
sem -> nversion;
|
||||
sem -> nimsets;
|
||||
sem -> semdata;
|
||||
sem -> evals;
|
||||
sem -> semfold;
|
||||
sem -> importer;
|
||||
sem -> procfind;
|
||||
sem -> lookups;
|
||||
sem -> rodread;
|
||||
sem -> pragmas;
|
||||
sem -> passes;
|
||||
rst -> os;
|
||||
rst -> msgs;
|
||||
rst -> strutils;
|
||||
rst -> platform;
|
||||
rst -> nhashes;
|
||||
rst -> ropes;
|
||||
rst -> options;
|
||||
highlite -> nhashes;
|
||||
highlite -> options;
|
||||
highlite -> msgs;
|
||||
highlite -> strutils;
|
||||
highlite -> platform;
|
||||
highlite -> idents;
|
||||
highlite -> lexbase;
|
||||
highlite -> wordrecg;
|
||||
highlite -> scanner;
|
||||
docgen -> ast;
|
||||
docgen -> astalgo;
|
||||
docgen -> strutils;
|
||||
docgen -> nhashes;
|
||||
docgen -> options;
|
||||
docgen -> nversion;
|
||||
docgen -> msgs;
|
||||
docgen -> os;
|
||||
docgen -> ropes;
|
||||
docgen -> idents;
|
||||
docgen -> wordrecg;
|
||||
docgen -> math;
|
||||
docgen -> syntaxes;
|
||||
docgen -> rnimsyn;
|
||||
docgen -> scanner;
|
||||
docgen -> rst;
|
||||
docgen -> times;
|
||||
docgen -> highlite;
|
||||
ccgutils -> ast;
|
||||
ccgutils -> astalgo;
|
||||
ccgutils -> ropes;
|
||||
ccgutils -> lists;
|
||||
ccgutils -> nhashes;
|
||||
ccgutils -> strutils;
|
||||
ccgutils -> types;
|
||||
ccgutils -> msgs;
|
||||
cgmeth -> options;
|
||||
cgmeth -> ast;
|
||||
cgmeth -> astalgo;
|
||||
cgmeth -> msgs;
|
||||
cgmeth -> idents;
|
||||
cgmeth -> rnimsyn;
|
||||
cgmeth -> types;
|
||||
cgmeth -> magicsys;
|
||||
cgen -> ast;
|
||||
cgen -> astalgo;
|
||||
cgen -> strutils;
|
||||
cgen -> nhashes;
|
||||
cgen -> trees;
|
||||
cgen -> platform;
|
||||
cgen -> magicsys;
|
||||
cgen -> extccomp;
|
||||
cgen -> options;
|
||||
cgen -> nversion;
|
||||
cgen -> nimsets;
|
||||
cgen -> msgs;
|
||||
cgen -> crc;
|
||||
cgen -> bitsets;
|
||||
cgen -> idents;
|
||||
cgen -> lists;
|
||||
cgen -> types;
|
||||
cgen -> ccgutils;
|
||||
cgen -> os;
|
||||
cgen -> times;
|
||||
cgen -> ropes;
|
||||
cgen -> math;
|
||||
cgen -> passes;
|
||||
cgen -> rodread;
|
||||
cgen -> wordrecg;
|
||||
cgen -> rnimsyn;
|
||||
cgen -> treetab;
|
||||
cgen -> cgmeth;
|
||||
jsgen -> ast;
|
||||
jsgen -> astalgo;
|
||||
jsgen -> strutils;
|
||||
jsgen -> nhashes;
|
||||
jsgen -> trees;
|
||||
jsgen -> platform;
|
||||
jsgen -> magicsys;
|
||||
jsgen -> extccomp;
|
||||
jsgen -> options;
|
||||
jsgen -> nversion;
|
||||
jsgen -> nimsets;
|
||||
jsgen -> msgs;
|
||||
jsgen -> crc;
|
||||
jsgen -> bitsets;
|
||||
jsgen -> idents;
|
||||
jsgen -> lists;
|
||||
jsgen -> types;
|
||||
jsgen -> os;
|
||||
jsgen -> times;
|
||||
jsgen -> ropes;
|
||||
jsgen -> math;
|
||||
jsgen -> passes;
|
||||
jsgen -> ccgutils;
|
||||
jsgen -> wordrecg;
|
||||
jsgen -> rnimsyn;
|
||||
jsgen -> rodread;
|
||||
interact -> llstream;
|
||||
interact -> strutils;
|
||||
interact -> ropes;
|
||||
interact -> nstrtabs;
|
||||
interact -> msgs;
|
||||
passaux -> strutils;
|
||||
passaux -> ast;
|
||||
passaux -> astalgo;
|
||||
passaux -> passes;
|
||||
passaux -> msgs;
|
||||
passaux -> options;
|
||||
depends -> os;
|
||||
depends -> options;
|
||||
depends -> ast;
|
||||
depends -> astalgo;
|
||||
depends -> msgs;
|
||||
depends -> ropes;
|
||||
depends -> idents;
|
||||
depends -> passes;
|
||||
depends -> importer;
|
||||
transf -> strutils;
|
||||
transf -> lists;
|
||||
transf -> options;
|
||||
transf -> ast;
|
||||
transf -> astalgo;
|
||||
transf -> trees;
|
||||
transf -> treetab;
|
||||
transf -> evals;
|
||||
transf -> msgs;
|
||||
transf -> os;
|
||||
transf -> idents;
|
||||
transf -> rnimsyn;
|
||||
transf -> types;
|
||||
transf -> passes;
|
||||
transf -> semfold;
|
||||
transf -> magicsys;
|
||||
transf -> cgmeth;
|
||||
main -> llstream;
|
||||
main -> strutils;
|
||||
main -> ast;
|
||||
main -> astalgo;
|
||||
main -> scanner;
|
||||
main -> syntaxes;
|
||||
main -> rnimsyn;
|
||||
main -> options;
|
||||
main -> msgs;
|
||||
main -> os;
|
||||
main -> lists;
|
||||
main -> condsyms;
|
||||
main -> paslex;
|
||||
main -> pasparse;
|
||||
main -> rodread;
|
||||
main -> rodwrite;
|
||||
main -> ropes;
|
||||
main -> trees;
|
||||
main -> wordrecg;
|
||||
main -> sem;
|
||||
main -> semdata;
|
||||
main -> idents;
|
||||
main -> passes;
|
||||
main -> docgen;
|
||||
main -> extccomp;
|
||||
main -> cgen;
|
||||
main -> jsgen;
|
||||
main -> platform;
|
||||
main -> interact;
|
||||
main -> nimconf;
|
||||
main -> importer;
|
||||
main -> passaux;
|
||||
main -> depends;
|
||||
main -> transf;
|
||||
main -> evals;
|
||||
main -> types;
|
||||
parseopt -> os;
|
||||
parseopt -> strutils;
|
||||
nimrod -> times;
|
||||
nimrod -> commands;
|
||||
nimrod -> scanner;
|
||||
nimrod -> condsyms;
|
||||
nimrod -> options;
|
||||
nimrod -> msgs;
|
||||
nimrod -> nversion;
|
||||
nimrod -> nimconf;
|
||||
nimrod -> ropes;
|
||||
nimrod -> extccomp;
|
||||
nimrod -> strutils;
|
||||
nimrod -> os;
|
||||
nimrod -> platform;
|
||||
nimrod -> main;
|
||||
nimrod -> parseopt;
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
[Project]
|
||||
Name: "Nimrod"
|
||||
Version: "$version"
|
||||
; Windows and i386 must be first!
|
||||
OS: "windows;linux;macosx;solaris;freebsd;netbsd;openbsd"
|
||||
CPU: "i386;amd64;powerpc64;arm" # ;sparc
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;amd64;powerpc64;arm;sparc;mips
|
||||
macosx: i386;amd64;powerpc64
|
||||
solaris: i386;amd64;sparc
|
||||
freebsd: i386;amd64
|
||||
netbsd: i386;amd64
|
||||
openbsd: i386;amd64
|
||||
haiku: i386;amd64
|
||||
"""
|
||||
|
||||
Authors: "Andreas Rumpf"
|
||||
Description: """This is the Nimrod Compiler. Nimrod is a new statically typed,
|
||||
imperative programming language, that supports procedural, functional, object
|
||||
@@ -35,9 +43,8 @@ Start: "doc/overview.html"
|
||||
|
||||
|
||||
[Other]
|
||||
Files: "readme.txt;install.txt;contributors.txt"
|
||||
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
|
||||
Files: "configure;makefile"
|
||||
Files: "gpl.html"
|
||||
Files: "*.ini"
|
||||
Files: "koch.nim"
|
||||
|
||||
@@ -54,6 +61,11 @@ Files: "compiler/readme.txt"
|
||||
Files: "compiler/nimrod.ini"
|
||||
Files: "compiler/nimrod.cfg"
|
||||
Files: "compiler/*.nim"
|
||||
Files: "compiler/c2nim/*.nim"
|
||||
Files: "compiler/c2nim/*.cfg"
|
||||
Files: "compiler/pas2nim/*.nim"
|
||||
Files: "compiler/pas2nim/*.cfg"
|
||||
|
||||
Files: "build/empty.txt"
|
||||
Files: "bin/empty.txt"
|
||||
|
||||
@@ -137,5 +149,5 @@ flags = "-w"
|
||||
buildDepends: "gcc (>= 4:4.3.2)"
|
||||
pkgDepends: "gcc (>= 4:4.3.2)"
|
||||
shortDesc: "The Nimrod Compiler"
|
||||
licenses: "bin/nimrod,gpl2;lib/*,lgpl;"
|
||||
licenses: "bin/nimrod,MIT;lib/*,MIT;"
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ when defined(gcc) and defined(windows):
|
||||
else:
|
||||
{.link: "icons/nimrod_icon.o".}
|
||||
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, platform, main, parseopt, service
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, osproc, platform, main, parseopt, service
|
||||
|
||||
when hasTinyCBackend:
|
||||
import tccgen
|
||||
@@ -23,7 +23,7 @@ when hasTinyCBackend:
|
||||
when defined(profiler) or defined(memProfiler):
|
||||
{.hint: "Profiling support is turned on!".}
|
||||
import nimprof
|
||||
|
||||
|
||||
proc prependCurDir(f: string): string =
|
||||
when defined(unix):
|
||||
if os.isAbsolute(f): result = f
|
||||
@@ -31,12 +31,12 @@ proc prependCurDir(f: string): string =
|
||||
else:
|
||||
result = f
|
||||
|
||||
proc HandleCmdLine() =
|
||||
proc handleCmdLine() =
|
||||
if paramCount() == 0:
|
||||
writeCommandLineUsage()
|
||||
else:
|
||||
# Process command line arguments:
|
||||
ProcessCmdLine(passCmd1, "")
|
||||
processCmdLine(passCmd1, "")
|
||||
if gProjectName != "":
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
@@ -47,12 +47,12 @@ proc HandleCmdLine() =
|
||||
gProjectName = p.name
|
||||
else:
|
||||
gProjectPath = getCurrentDir()
|
||||
LoadConfigs(DefaultConfig) # load all config files
|
||||
loadConfigs(DefaultConfig) # load all config files
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
extccomp.initVars()
|
||||
ProcessCmdLine(passCmd2, "")
|
||||
MainCommand()
|
||||
processCmdLine(passCmd2, "")
|
||||
mainCommand()
|
||||
if gVerbosity >= 2: echo(GC_getStatistics())
|
||||
#echo(GC_getStatistics())
|
||||
if msgs.gErrorCounter == 0:
|
||||
@@ -61,12 +61,22 @@ proc HandleCmdLine() =
|
||||
tccgen.run()
|
||||
if optRun in gGlobalOptions:
|
||||
if gCmd == cmdCompileToJS:
|
||||
var ex = quoteIfContainsWhite(
|
||||
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
||||
var ex: string
|
||||
if options.outFile.len > 0:
|
||||
ex = options.outFile.prependCurDir.quoteShell
|
||||
else:
|
||||
ex = quoteShell(
|
||||
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
||||
execExternalProgram("node " & ex & ' ' & service.arguments)
|
||||
else:
|
||||
var ex = quoteIfContainsWhite(
|
||||
changeFileExt(gProjectFull, exeExt).prependCurDir)
|
||||
var binPath: string
|
||||
if options.outFile.len > 0:
|
||||
# If the user specified an outFile path, use that directly.
|
||||
binPath = options.outFile.prependCurDir
|
||||
else:
|
||||
# Figure out ourselves a valid binary name.
|
||||
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
|
||||
var ex = quoteShell(binPath)
|
||||
execExternalProgram(ex & ' ' & service.arguments)
|
||||
|
||||
when defined(GC_setMaxPause):
|
||||
@@ -75,6 +85,8 @@ when defined(GC_setMaxPause):
|
||||
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||
# the new correct mark&sweet collector is too slow :-/
|
||||
GC_disableMarkAndSweep()
|
||||
condsyms.InitDefines()
|
||||
HandleCmdLine()
|
||||
quit(int8(msgs.gErrorCounter > 0))
|
||||
condsyms.initDefines()
|
||||
|
||||
when not defined(selftest):
|
||||
handleCmdLine()
|
||||
quit(int8(msgs.gErrorCounter > 0))
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
mainModule:"nimrod.nim"
|
||||
|
||||
# gc:markAndSweep
|
||||
|
||||
hint[XDeclaredButNotUsed]:off
|
||||
path:"llvm"
|
||||
path:"$projectPath/.."
|
||||
@@ -9,4 +11,13 @@ path:"$projectPath/.."
|
||||
path:"$lib/packages/docutils"
|
||||
|
||||
define:booting
|
||||
import:testability
|
||||
|
||||
@if windows:
|
||||
cincludes: "$lib/wrappers/libffi/common"
|
||||
@end
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
|
||||
cs:partial
|
||||
#define:useNodeIds
|
||||
@@ -18,7 +18,7 @@ proc overlap*(a, b: PNode): bool
|
||||
proc inSet*(s: PNode, elem: PNode): bool
|
||||
proc someInSet*(s: PNode, a, b: PNode): bool
|
||||
proc emptyRange*(a, b: PNode): bool
|
||||
proc SetHasRange*(s: PNode): bool
|
||||
proc setHasRange*(s: PNode): bool
|
||||
# returns true if set contains a range (needed by the code generator)
|
||||
# these are used for constant folding:
|
||||
proc unionSets*(a, b: PNode): PNode
|
||||
@@ -32,7 +32,7 @@ proc cardSet*(s: PNode): BiggestInt
|
||||
|
||||
proc inSet(s: PNode, elem: PNode): bool =
|
||||
if s.kind != nkCurly:
|
||||
InternalError(s.info, "inSet")
|
||||
internalError(s.info, "inSet")
|
||||
return false
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
@@ -58,10 +58,10 @@ proc overlap(a, b: PNode): bool =
|
||||
else:
|
||||
result = sameValue(a, b)
|
||||
|
||||
proc SomeInSet(s: PNode, a, b: PNode): bool =
|
||||
proc someInSet(s: PNode, a, b: PNode): bool =
|
||||
# checks if some element of a..b is in the set s
|
||||
if s.kind != nkCurly:
|
||||
InternalError(s.info, "SomeInSet")
|
||||
internalError(s.info, "SomeInSet")
|
||||
return false
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
@@ -82,12 +82,12 @@ proc toBitSet(s: PNode, b: var TBitSet) =
|
||||
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)
|
||||
bitSetIncl(b, j - first)
|
||||
inc(j)
|
||||
else:
|
||||
BitSetIncl(b, getOrdValue(s.sons[i]) - first)
|
||||
bitSetIncl(b, getOrdValue(s.sons[i]) - first)
|
||||
|
||||
proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
var
|
||||
a, b, e, first: BiggestInt # a, b are interval borders
|
||||
elemType: PType
|
||||
@@ -98,14 +98,14 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
result.typ = settype
|
||||
result.info = info
|
||||
e = 0
|
||||
while e < len(s) * elemSize:
|
||||
while e < len(s) * ElemSize:
|
||||
if bitSetIn(s, e):
|
||||
a = e
|
||||
b = e
|
||||
while true:
|
||||
Inc(b)
|
||||
if (b >= len(s) * elemSize) or not bitSetIn(s, b): break
|
||||
Dec(b)
|
||||
inc(b)
|
||||
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
|
||||
dec(b)
|
||||
if a == b:
|
||||
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))
|
||||
else:
|
||||
@@ -115,34 +115,19 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
addSon(n, newIntTypeNode(nkIntLit, b + first, elemType))
|
||||
addSon(result, n)
|
||||
e = b
|
||||
Inc(e)
|
||||
inc(e)
|
||||
|
||||
type
|
||||
TSetOP = enum
|
||||
soUnion, soDiff, soSymDiff, soIntersect
|
||||
|
||||
proc nodeSetOp(a, b: PNode, op: TSetOp): PNode =
|
||||
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
|
||||
var x, y: TBitSet
|
||||
toBitSet(a, x)
|
||||
toBitSet(b, y)
|
||||
case op
|
||||
of soUnion: BitSetUnion(x, y)
|
||||
of soDiff: BitSetDiff(x, y)
|
||||
of soSymDiff: BitSetSymDiff(x, y)
|
||||
of soIntersect: BitSetIntersect(x, y)
|
||||
op(x, y)
|
||||
result = toTreeSet(x, a.typ, a.info)
|
||||
|
||||
proc unionSets(a, b: PNode): PNode =
|
||||
result = nodeSetOp(a, b, soUnion)
|
||||
|
||||
proc diffSets(a, b: PNode): PNode =
|
||||
result = nodeSetOp(a, b, soDiff)
|
||||
|
||||
proc intersectSets(a, b: PNode): PNode =
|
||||
result = nodeSetOp(a, b, soIntersect)
|
||||
|
||||
proc symdiffSets(a, b: PNode): PNode =
|
||||
result = nodeSetOp(a, b, soSymDiff)
|
||||
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
|
||||
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
|
||||
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
|
||||
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
|
||||
|
||||
proc containsSets(a, b: PNode): bool =
|
||||
var x, y: TBitSet
|
||||
@@ -156,6 +141,12 @@ proc equalSets(a, b: PNode): bool =
|
||||
toBitSet(b, y)
|
||||
result = bitSetEquals(x, y)
|
||||
|
||||
proc complement*(a: PNode): PNode =
|
||||
var x: TBitSet
|
||||
toBitSet(a, x)
|
||||
for i in countup(0, high(x)): x[i] = not x[i]
|
||||
result = toTreeSet(x, a.typ, a.info)
|
||||
|
||||
proc cardSet(s: PNode): BiggestInt =
|
||||
# here we can do better than converting it into a compact set
|
||||
# we just count the elements directly
|
||||
@@ -165,11 +156,11 @@ proc cardSet(s: PNode): BiggestInt =
|
||||
result = result + getOrdValue(s.sons[i].sons[1]) -
|
||||
getOrdValue(s.sons[i].sons[0]) + 1
|
||||
else:
|
||||
Inc(result)
|
||||
inc(result)
|
||||
|
||||
proc SetHasRange(s: PNode): bool =
|
||||
proc setHasRange(s: PNode): bool =
|
||||
if s.kind != nkCurly:
|
||||
InternalError(s.info, "SetHasRange")
|
||||
internalError(s.info, "SetHasRange")
|
||||
return false
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -15,8 +15,8 @@ const
|
||||
defaultAsmMarkerSymbol* = '!'
|
||||
VersionMajor* = 0
|
||||
VersionMinor* = 9
|
||||
VersionPatch* = 2
|
||||
VersionPatch* = 4
|
||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
||||
|
||||
RodFileVersion* = "1212" # modify this if the rod-format changes!
|
||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
#
|
||||
|
||||
import
|
||||
os, lists, strutils, strtabs
|
||||
os, lists, strutils, strtabs, osproc, sets
|
||||
|
||||
const
|
||||
hasTinyCBackend* = defined(tinyc)
|
||||
useEffectSystem* = true
|
||||
hasFFI* = defined(useFFI)
|
||||
newScopeForIf* = false # XXX activate for 0.9.4
|
||||
newScopeForIf* = true
|
||||
useCaas* = not defined(noCaas)
|
||||
noTimeMachine = defined(avoidTimeMachine) and defined(macosx)
|
||||
|
||||
type # please make sure we have under 32 options
|
||||
# (improves code efficiency a lot!)
|
||||
@@ -92,13 +94,15 @@ var
|
||||
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||
optHints, optStackTrace, optLineTrace,
|
||||
optPatterns}
|
||||
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
|
||||
optPatterns, optNilCheck}
|
||||
gGlobalOptions*: TGlobalOptions = {}
|
||||
gExitcode*: int8
|
||||
gCmd*: TCommands = cmdNone # the command
|
||||
gSelectedGC* = gcRefc # the selected GC
|
||||
searchPaths*, lazyPaths*: TLinkedList
|
||||
outFile*: string = ""
|
||||
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
|
||||
# The string uses the formatting variables `path` and `line`.
|
||||
headerFile*: string = ""
|
||||
gVerbosity* = 1 # how verbose the compiler is
|
||||
gNumberOfProcessors*: int # number of processors
|
||||
@@ -110,6 +114,7 @@ var
|
||||
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
|
||||
# the tracked source X, saved by the CAAS client.
|
||||
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
|
||||
gNoBabelPath* = false
|
||||
|
||||
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
||||
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
|
||||
@@ -131,6 +136,7 @@ const
|
||||
NimExt* = "nim"
|
||||
RodExt* = "rod"
|
||||
HtmlExt* = "html"
|
||||
JsonExt* = "json"
|
||||
TexExt* = "tex"
|
||||
IniExt* = "ini"
|
||||
DefaultConfig* = "nimrod.cfg"
|
||||
@@ -140,7 +146,7 @@ const
|
||||
# additional configuration variables:
|
||||
var
|
||||
gConfigVars* = newStringTable(modeStyleInsensitive)
|
||||
gDllOverrides = newStringtable(modeCaseInsensitive)
|
||||
gDllOverrides = newStringTable(modeCaseInsensitive)
|
||||
libpath* = ""
|
||||
gProjectName* = "" # holds a name like 'nimrod'
|
||||
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
||||
@@ -180,7 +186,7 @@ proc getOutFile*(filename, ext: string): string =
|
||||
|
||||
proc getPrefixDir*(): string =
|
||||
## gets the application directory
|
||||
result = SplitPath(getAppDir()).head
|
||||
result = splitPath(getAppDir()).head
|
||||
|
||||
proc canonicalizePath*(path: string): string =
|
||||
result = path.expandFilename
|
||||
@@ -188,16 +194,16 @@ proc canonicalizePath*(path: string): string =
|
||||
|
||||
proc shortenDir*(dir: string): string =
|
||||
## returns the interesting part of a dir
|
||||
var prefix = getPrefixDir() & dirSep
|
||||
var prefix = getPrefixDir() & DirSep
|
||||
if startsWith(dir, prefix):
|
||||
return substr(dir, len(prefix))
|
||||
prefix = gProjectPath & dirSep
|
||||
prefix = gProjectPath & DirSep
|
||||
if startsWith(dir, prefix):
|
||||
return substr(dir, len(prefix))
|
||||
result = dir
|
||||
|
||||
proc removeTrailingDirSep*(path: string): string =
|
||||
if (len(path) > 0) and (path[len(path) - 1] == dirSep):
|
||||
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
|
||||
result = substr(path, 0, len(path) - 2)
|
||||
else:
|
||||
result = path
|
||||
@@ -205,7 +211,52 @@ proc removeTrailingDirSep*(path: string): string =
|
||||
proc getGeneratedPath: string =
|
||||
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
|
||||
genSubDir
|
||||
|
||||
|
||||
template newPackageCache(): expr =
|
||||
newStringTable(when FileSystemCaseSensitive:
|
||||
modeCaseInsensitive
|
||||
else:
|
||||
modeCaseSensitive)
|
||||
|
||||
var packageCache = newPackageCache()
|
||||
|
||||
proc resetPackageCache*() = packageCache = newPackageCache()
|
||||
|
||||
iterator myParentDirs(p: string): string =
|
||||
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
|
||||
var current = p
|
||||
while true:
|
||||
current = current.parentDir
|
||||
if current.len == 0: break
|
||||
yield current
|
||||
|
||||
proc getPackageName*(path: string): string =
|
||||
var parents = 0
|
||||
block packageSearch:
|
||||
for d in myParentDirs(path):
|
||||
if packageCache.hasKey(d):
|
||||
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
|
||||
return packageCache[d]
|
||||
inc parents
|
||||
for file in walkFiles(d / "*.babel"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
# we also store if we didn't find anything:
|
||||
if result.isNil: result = ""
|
||||
for d in myParentDirs(path):
|
||||
#echo "set cache ", d, " |", result, "|", parents
|
||||
packageCache[d] = result
|
||||
dec parents
|
||||
if parents <= 0: break
|
||||
|
||||
proc withPackageName*(path: string): string =
|
||||
let x = path.getPackageName
|
||||
if x.len == 0:
|
||||
result = path
|
||||
else:
|
||||
let (p, file, ext) = path.splitFile
|
||||
result = (p / (x & '_' & file)) & ext
|
||||
|
||||
proc toGeneratedFile*(path, ext: string): string =
|
||||
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
|
||||
var (head, tail) = splitPath(path)
|
||||
@@ -213,6 +264,28 @@ proc toGeneratedFile*(path, ext: string): string =
|
||||
result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)])
|
||||
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
|
||||
|
||||
when noTimeMachine:
|
||||
var alreadyExcludedDirs = initSet[string]()
|
||||
proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
|
||||
## Calls a macosx command on the directory to exclude it from backups.
|
||||
##
|
||||
## The macosx tmutil command is invoked to mark the specified path as an
|
||||
## item to be excluded from time machine backups. If a path already exists
|
||||
## with files before excluding it, newer files won't be added to the
|
||||
## directory, but previous files won't be removed from the backup until the
|
||||
## user deletes that directory.
|
||||
##
|
||||
## The whole proc is optional and will ignore all kinds of errors. The only
|
||||
## way to be sure that it works is to call ``tmutil isexcluded path``.
|
||||
if alreadyExcludedDirs.contains(dir): return
|
||||
alreadyExcludedDirs.incl(dir)
|
||||
try:
|
||||
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
|
||||
discard p.waitForExit
|
||||
p.close
|
||||
except E_Base, EOS:
|
||||
discard
|
||||
|
||||
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||
var (head, tail) = splitPath(f)
|
||||
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
||||
@@ -220,21 +293,23 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||
if createSubDir:
|
||||
try:
|
||||
createDir(subdir)
|
||||
when noTimeMachine:
|
||||
excludeDirFromTimeMachine(subdir)
|
||||
except EOS:
|
||||
writeln(stdout, "cannot create directory: " & subdir)
|
||||
quit(1)
|
||||
result = joinPath(subdir, tail)
|
||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||
|
||||
iterator iterSearchPath*(SearchPaths: TLinkedList): string =
|
||||
var it = PStrEntry(SearchPaths.head)
|
||||
iterator iterSearchPath*(searchPaths: TLinkedList): string =
|
||||
var it = PStrEntry(searchPaths.head)
|
||||
while it != nil:
|
||||
yield it.data
|
||||
it = PStrEntry(it.Next)
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc rawFindFile(f: string): string =
|
||||
for it in iterSearchPath(SearchPaths):
|
||||
result = JoinPath(it, f)
|
||||
for it in iterSearchPath(searchPaths):
|
||||
result = joinPath(it, f)
|
||||
if existsFile(result):
|
||||
return result.canonicalizePath
|
||||
result = ""
|
||||
@@ -242,14 +317,14 @@ proc rawFindFile(f: string): string =
|
||||
proc rawFindFile2(f: string): string =
|
||||
var it = PStrEntry(lazyPaths.head)
|
||||
while it != nil:
|
||||
result = JoinPath(it.data, f)
|
||||
result = joinPath(it.data, f)
|
||||
if existsFile(result):
|
||||
bringToFront(lazyPaths, it)
|
||||
return result.canonicalizePath
|
||||
it = PStrEntry(it.Next)
|
||||
it = PStrEntry(it.next)
|
||||
result = ""
|
||||
|
||||
proc FindFile*(f: string): string {.procvar.} =
|
||||
proc findFile*(f: string): string {.procvar.} =
|
||||
result = f.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile
|
||||
@@ -258,9 +333,13 @@ proc FindFile*(f: string): string {.procvar.} =
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile2
|
||||
|
||||
proc findModule*(modulename: string): string {.inline.} =
|
||||
proc findModule*(modulename, currentModule: string): string =
|
||||
# returns path to module
|
||||
result = FindFile(AddFileExt(modulename, nimExt))
|
||||
let m = addFileExt(modulename, NimExt)
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
result = findFile(m)
|
||||
|
||||
proc libCandidates*(s: string, dest: var seq[string]) =
|
||||
var le = strutils.find(s, '(')
|
||||
@@ -287,7 +366,7 @@ proc inclDynlibOverride*(lib: string) =
|
||||
proc isDynlibOverride*(lib: string): bool =
|
||||
result = gDllOverrides.hasKey(lib.canonDynlibName)
|
||||
|
||||
proc binaryStrSearch*(x: openarray[string], y: string): int =
|
||||
proc binaryStrSearch*(x: openArray[string], y: string): int =
|
||||
var a = 0
|
||||
var b = len(x) - 1
|
||||
while a <= b:
|
||||
|
||||
@@ -42,7 +42,7 @@ const
|
||||
MaxStackSize* = 64 ## max required stack size by the VM
|
||||
|
||||
proc patternError(n: PNode) =
|
||||
LocalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
|
||||
add(code, chr(ord(op)))
|
||||
@@ -50,6 +50,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
|
||||
proc whichAlias*(p: PSym): TAliasRequest =
|
||||
if p.constraint != nil:
|
||||
result = TAliasRequest(p.constraint.strVal[0].ord)
|
||||
else:
|
||||
result = aqNone
|
||||
|
||||
proc compileConstraints(p: PNode, result: var TPatternCode) =
|
||||
case p.kind
|
||||
@@ -95,14 +97,14 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
|
||||
of "nosideeffect": result.add(ppNoSideEffect)
|
||||
else:
|
||||
# check all symkinds:
|
||||
InternalAssert int(high(TSymKind)) < 255
|
||||
internalAssert int(high(TSymKind)) < 255
|
||||
for i in low(TSymKind)..high(TSymKind):
|
||||
if cmpIgnoreStyle(($i).substr(2), spec) == 0:
|
||||
result.add(ppSymKind)
|
||||
result.add(chr(i.ord))
|
||||
return
|
||||
# check all nodekinds:
|
||||
InternalAssert int(high(TNodeKind)) < 255
|
||||
internalAssert int(high(TNodeKind)) < 255
|
||||
for i in low(TNodeKind)..high(TNodeKind):
|
||||
if cmpIgnoreStyle($i, spec) == 0:
|
||||
result.add(ppNodeKind)
|
||||
@@ -122,8 +124,8 @@ proc semNodeKindConstraints*(p: PNode): PNode =
|
||||
if p.len >= 2:
|
||||
for i in 1.. <p.len:
|
||||
compileConstraints(p.sons[i], result.strVal)
|
||||
if result.strVal.len > maxStackSize-1:
|
||||
InternalError(p.info, "parameter pattern too complex")
|
||||
if result.strVal.len > MaxStackSize-1:
|
||||
internalError(p.info, "parameter pattern too complex")
|
||||
else:
|
||||
patternError(p)
|
||||
result.strVal.add(ppEof)
|
||||
@@ -214,12 +216,12 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isAssignable(owner, n.sons[0])
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
proc matchNodeKinds*(p, n: PNode): bool =
|
||||
# matches the parameter constraint 'p' against the concrete AST 'n'.
|
||||
# Efficiency matters here.
|
||||
var stack {.noinit.}: array[0..maxStackSize, bool]
|
||||
var stack {.noinit.}: array[0..MaxStackSize, bool]
|
||||
# empty patterns are true:
|
||||
stack[0] = true
|
||||
var sp = 1
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# A HIGH-PERFORMANCE configuration file parser;
|
||||
# the Nimrod version of this file is part of the
|
||||
# standard library.
|
||||
|
||||
import
|
||||
llstream, nhashes, strutils, nimlexbase
|
||||
|
||||
type
|
||||
TCfgEventKind* = enum
|
||||
cfgEof, # end of file reached
|
||||
cfgSectionStart, # a ``[section]`` has been parsed
|
||||
cfgKeyValuePair, # a ``key=value`` pair has been detected
|
||||
cfgOption, # a ``--key=value`` command line option
|
||||
cfgError # an error ocurred during parsing; msg contains the
|
||||
# error message
|
||||
TCfgEvent* = object of TObject
|
||||
case kind*: TCfgEventKind
|
||||
of cfgEof:
|
||||
nil
|
||||
|
||||
of cfgSectionStart:
|
||||
section*: string
|
||||
|
||||
of cfgKeyValuePair, cfgOption:
|
||||
key*, value*: string
|
||||
|
||||
of cfgError:
|
||||
msg*: string
|
||||
|
||||
|
||||
TTokKind* = enum
|
||||
tkInvalid, tkEof, # order is important here!
|
||||
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
|
||||
TToken*{.final.} = object # a token
|
||||
kind*: TTokKind # the type of the token
|
||||
literal*: string # the parsed (string) literal
|
||||
|
||||
TParserState* = enum
|
||||
startState, commaState
|
||||
TCfgParser* = object of TBaseLexer
|
||||
tok*: TToken
|
||||
state*: TParserState
|
||||
filename*: string
|
||||
|
||||
|
||||
proc Open*(c: var TCfgParser, filename: string, inputStream: PLLStream)
|
||||
proc Close*(c: var TCfgParser)
|
||||
proc next*(c: var TCfgParser): TCfgEvent
|
||||
proc getColumn*(c: TCfgParser): int
|
||||
proc getLine*(c: TCfgParser): int
|
||||
proc getFilename*(c: TCfgParser): string
|
||||
proc errorStr*(c: TCfgParser, msg: string): string
|
||||
# implementation
|
||||
|
||||
const
|
||||
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'} #
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
proc rawGetTok(c: var TCfgParser, tok: var TToken)
|
||||
proc open(c: var TCfgParser, filename: string, inputStream: PLLStream) =
|
||||
openBaseLexer(c, inputStream)
|
||||
c.filename = filename
|
||||
c.state = startState
|
||||
c.tok.kind = tkInvalid
|
||||
c.tok.literal = ""
|
||||
rawGetTok(c, c.tok)
|
||||
|
||||
proc close(c: var TCfgParser) =
|
||||
closeBaseLexer(c)
|
||||
|
||||
proc getColumn(c: TCfgParser): int =
|
||||
result = getColNumber(c, c.bufPos)
|
||||
|
||||
proc getLine(c: TCfgParser): int =
|
||||
result = c.linenumber
|
||||
|
||||
proc getFilename(c: TCfgParser): string =
|
||||
result = c.filename
|
||||
|
||||
proc handleHexChar(c: var TCfgParser, xi: var int) =
|
||||
case c.buf[c.bufpos]
|
||||
of '0'..'9':
|
||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
|
||||
inc(c.bufpos)
|
||||
of 'a'..'f':
|
||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
|
||||
inc(c.bufpos)
|
||||
of 'A'..'F':
|
||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
|
||||
inc(c.bufpos)
|
||||
else:
|
||||
nil
|
||||
|
||||
proc handleDecChars(c: var TCfgParser, xi: var int) =
|
||||
while c.buf[c.bufpos] in {'0'..'9'}:
|
||||
xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'))
|
||||
inc(c.bufpos)
|
||||
|
||||
proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
|
||||
var xi: int
|
||||
inc(c.bufpos) # skip '\'
|
||||
case c.buf[c.bufpos]
|
||||
of 'n', 'N':
|
||||
tok.literal = tok.literal & "\n"
|
||||
Inc(c.bufpos)
|
||||
of 'r', 'R', 'c', 'C':
|
||||
add(tok.literal, CR)
|
||||
Inc(c.bufpos)
|
||||
of 'l', 'L':
|
||||
add(tok.literal, LF)
|
||||
Inc(c.bufpos)
|
||||
of 'f', 'F':
|
||||
add(tok.literal, FF)
|
||||
inc(c.bufpos)
|
||||
of 'e', 'E':
|
||||
add(tok.literal, ESC)
|
||||
Inc(c.bufpos)
|
||||
of 'a', 'A':
|
||||
add(tok.literal, BEL)
|
||||
Inc(c.bufpos)
|
||||
of 'b', 'B':
|
||||
add(tok.literal, BACKSPACE)
|
||||
Inc(c.bufpos)
|
||||
of 'v', 'V':
|
||||
add(tok.literal, VT)
|
||||
Inc(c.bufpos)
|
||||
of 't', 'T':
|
||||
add(tok.literal, Tabulator)
|
||||
Inc(c.bufpos)
|
||||
of '\'', '\"':
|
||||
add(tok.literal, c.buf[c.bufpos])
|
||||
Inc(c.bufpos)
|
||||
of '\\':
|
||||
add(tok.literal, '\\')
|
||||
Inc(c.bufpos)
|
||||
of 'x', 'X':
|
||||
inc(c.bufpos)
|
||||
xi = 0
|
||||
handleHexChar(c, xi)
|
||||
handleHexChar(c, xi)
|
||||
add(tok.literal, Chr(xi))
|
||||
of '0'..'9':
|
||||
xi = 0
|
||||
handleDecChars(c, xi)
|
||||
if (xi <= 255): add(tok.literal, Chr(xi))
|
||||
else: tok.kind = tkInvalid
|
||||
else: tok.kind = tkInvalid
|
||||
|
||||
proc HandleCRLF(c: var TCfgParser, pos: int): int =
|
||||
case c.buf[pos]
|
||||
of CR: result = lexbase.HandleCR(c, pos)
|
||||
of LF: result = lexbase.HandleLF(c, pos)
|
||||
else: result = pos
|
||||
|
||||
proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
|
||||
var
|
||||
pos: int
|
||||
ch: Char
|
||||
buf: cstring
|
||||
pos = c.bufPos + 1 # skip "
|
||||
buf = c.buf # put `buf` in a register
|
||||
tok.kind = tkSymbol
|
||||
if (buf[pos] == '\"') and (buf[pos + 1] == '\"'):
|
||||
# long string literal:
|
||||
inc(pos, 2) # skip ""
|
||||
# skip leading newline:
|
||||
pos = HandleCRLF(c, pos)
|
||||
buf = c.buf
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\"':
|
||||
if (buf[pos + 1] == '\"') and (buf[pos + 2] == '\"'): break
|
||||
add(tok.literal, '\"')
|
||||
Inc(pos)
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(c, pos)
|
||||
buf = c.buf
|
||||
tok.literal = tok.literal & "\n"
|
||||
of lexbase.EndOfFile:
|
||||
tok.kind = tkInvalid
|
||||
break
|
||||
else:
|
||||
add(tok.literal, buf[pos])
|
||||
Inc(pos)
|
||||
c.bufpos = pos +
|
||||
3 # skip the three """
|
||||
else:
|
||||
# ordinary string literal
|
||||
while true:
|
||||
ch = buf[pos]
|
||||
if ch == '\"':
|
||||
inc(pos) # skip '"'
|
||||
break
|
||||
if ch in {CR, LF, lexbase.EndOfFile}:
|
||||
tok.kind = tkInvalid
|
||||
break
|
||||
if (ch == '\\') and not rawMode:
|
||||
c.bufPos = pos
|
||||
getEscapedChar(c, tok)
|
||||
pos = c.bufPos
|
||||
else:
|
||||
add(tok.literal, ch)
|
||||
Inc(pos)
|
||||
c.bufpos = pos
|
||||
|
||||
proc getSymbol(c: var TCfgParser, tok: var TToken) =
|
||||
var
|
||||
pos: int
|
||||
buf: cstring
|
||||
pos = c.bufpos
|
||||
buf = c.buf
|
||||
while true:
|
||||
add(tok.literal, buf[pos])
|
||||
Inc(pos)
|
||||
if not (buf[pos] in SymChars): break
|
||||
c.bufpos = pos
|
||||
tok.kind = tkSymbol
|
||||
|
||||
proc skip(c: var TCfgParser) =
|
||||
var
|
||||
buf: cstring
|
||||
pos: int
|
||||
pos = c.bufpos
|
||||
buf = c.buf
|
||||
while true:
|
||||
case buf[pos]
|
||||
of ' ':
|
||||
Inc(pos)
|
||||
of Tabulator:
|
||||
inc(pos)
|
||||
of '#', ';':
|
||||
while not (buf[pos] in {CR, LF, lexbase.EndOfFile}): inc(pos)
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(c, pos)
|
||||
buf = c.buf
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
c.bufpos = pos
|
||||
|
||||
proc rawGetTok(c: var TCfgParser, tok: var TToken) =
|
||||
tok.kind = tkInvalid
|
||||
setlen(tok.literal, 0)
|
||||
skip(c)
|
||||
case c.buf[c.bufpos]
|
||||
of '=':
|
||||
tok.kind = tkEquals
|
||||
inc(c.bufpos)
|
||||
tok.literal = "="
|
||||
of '-':
|
||||
inc(c.bufPos)
|
||||
if c.buf[c.bufPos] == '-': inc(c.bufPos)
|
||||
tok.kind = tkDashDash
|
||||
tok.literal = "--"
|
||||
of ':':
|
||||
tok.kind = tkColon
|
||||
inc(c.bufpos)
|
||||
tok.literal = ":"
|
||||
of 'r', 'R':
|
||||
if c.buf[c.bufPos + 1] == '\"':
|
||||
Inc(c.bufPos)
|
||||
getString(c, tok, true)
|
||||
else:
|
||||
getSymbol(c, tok)
|
||||
of '[':
|
||||
tok.kind = tkBracketLe
|
||||
inc(c.bufpos)
|
||||
tok.literal = "["
|
||||
of ']':
|
||||
tok.kind = tkBracketRi
|
||||
Inc(c.bufpos)
|
||||
tok.literal = "]"
|
||||
of '\"':
|
||||
getString(c, tok, false)
|
||||
of lexbase.EndOfFile:
|
||||
tok.kind = tkEof
|
||||
else: getSymbol(c, tok)
|
||||
|
||||
proc errorStr(c: TCfgParser, msg: string): string =
|
||||
result = `%`("$1($2, $3) Error: $4",
|
||||
[c.filename, $(getLine(c)), $(getColumn(c)), msg])
|
||||
|
||||
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
|
||||
if c.tok.kind == tkSymbol:
|
||||
result.kind = kind
|
||||
result.key = c.tok.literal
|
||||
result.value = ""
|
||||
rawGetTok(c, c.tok)
|
||||
while c.tok.literal == ".":
|
||||
add(result.key, '.')
|
||||
rawGetTok(c, c.tok)
|
||||
if c.tok.kind == tkSymbol:
|
||||
add(result.key, c.tok.literal)
|
||||
rawGetTok(c, c.tok)
|
||||
else:
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
||||
break
|
||||
if c.tok.kind in {tkEquals, tkColon}:
|
||||
rawGetTok(c, c.tok)
|
||||
if c.tok.kind == tkSymbol:
|
||||
result.value = c.tok.literal
|
||||
else:
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
||||
rawGetTok(c, c.tok)
|
||||
else:
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
||||
rawGetTok(c, c.tok)
|
||||
|
||||
proc next(c: var TCfgParser): TCfgEvent =
|
||||
case c.tok.kind
|
||||
of tkEof:
|
||||
result.kind = cfgEof
|
||||
of tkDashDash:
|
||||
rawGetTok(c, c.tok)
|
||||
result = getKeyValPair(c, cfgOption)
|
||||
of tkSymbol:
|
||||
result = getKeyValPair(c, cfgKeyValuePair)
|
||||
of tkBracketLe:
|
||||
rawGetTok(c, c.tok)
|
||||
if c.tok.kind == tkSymbol:
|
||||
result.kind = cfgSectionStart
|
||||
result.section = c.tok.literal
|
||||
else:
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
||||
rawGetTok(c, c.tok)
|
||||
if c.tok.kind == tkBracketRi:
|
||||
rawGetTok(c, c.tok)
|
||||
else:
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "\']\' expected, but found: " & c.tok.literal)
|
||||
of tkInvalid, tkBracketRi, tkEquals, tkColon:
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "invalid token: " & c.tok.literal)
|
||||
rawGetTok(c, c.tok)
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -18,10 +18,10 @@
|
||||
# In fact the grammar is generated from this file:
|
||||
when isMainModule:
|
||||
import pegs
|
||||
var outp = open("compiler/grammar.txt", fmWrite)
|
||||
var outp = open("doc/grammar.txt", fmWrite)
|
||||
for line in lines("compiler/parser.nim"):
|
||||
if line =~ peg" \s* '#| ' {.*}":
|
||||
outp.writeln matches[0]
|
||||
outp.write matches[0], "\L"
|
||||
outp.close
|
||||
|
||||
import
|
||||
@@ -31,12 +31,13 @@ type
|
||||
TParser*{.final.} = object # a TParser object represents a module that
|
||||
# is being parsed
|
||||
currInd: int # current indentation
|
||||
firstTok: bool
|
||||
firstTok, strongSpaces: bool
|
||||
lex*: TLexer # the lexer that is used for parsing
|
||||
tok*: TToken # the current token
|
||||
inPragma: int
|
||||
inSemiStmtList: int
|
||||
|
||||
proc ParseAll*(p: var TParser): PNode
|
||||
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
|
||||
proc parseAll*(p: var TParser): PNode
|
||||
proc closeParser*(p: var TParser)
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode
|
||||
# implements an iterator. Returns the next top-level statement or
|
||||
@@ -48,7 +49,6 @@ proc parseString*(s: string, filename: string = "", line: int = 0): PNode
|
||||
# correct error messages referring to the original source.
|
||||
|
||||
# helpers for the other parsers
|
||||
proc getPrecedence*(tok: TToken): int
|
||||
proc isOperator*(tok: TToken): bool
|
||||
proc getTok*(p: var TParser)
|
||||
proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "")
|
||||
@@ -59,15 +59,15 @@ proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode
|
||||
proc newStrNodeP*(kind: TNodeKind, strVal: string, p: TParser): PNode
|
||||
proc newIdentNodeP*(ident: PIdent, p: TParser): PNode
|
||||
proc expectIdentOrKeyw*(p: TParser)
|
||||
proc ExpectIdent*(p: TParser)
|
||||
proc expectIdent*(p: TParser)
|
||||
proc parLineInfo*(p: TParser): TLineInfo
|
||||
proc Eat*(p: var TParser, TokType: TTokType)
|
||||
proc eat*(p: var TParser, tokType: TTokType)
|
||||
proc skipInd*(p: var TParser)
|
||||
proc optPar*(p: var TParser)
|
||||
proc optInd*(p: var TParser, n: PNode)
|
||||
proc indAndComment*(p: var TParser, n: PNode)
|
||||
proc setBaseFlags*(n: PNode, base: TNumericalBase)
|
||||
proc parseSymbol*(p: var TParser): PNode
|
||||
proc parseSymbol*(p: var TParser, allowNil = false): PNode
|
||||
proc parseTry(p: var TParser): PNode
|
||||
proc parseCase(p: var TParser): PNode
|
||||
# implementation
|
||||
@@ -75,17 +75,20 @@ proc parseCase(p: var TParser): PNode
|
||||
proc getTok(p: var TParser) =
|
||||
rawGetTok(p.lex, p.tok)
|
||||
|
||||
proc OpenParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream) =
|
||||
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
|
||||
strongSpaces=false) =
|
||||
initToken(p.tok)
|
||||
OpenLexer(p.lex, fileIdx, inputstream)
|
||||
openLexer(p.lex, fileIdx, inputStream)
|
||||
getTok(p) # read the first token
|
||||
p.firstTok = true
|
||||
p.strongSpaces = strongSpaces
|
||||
|
||||
proc OpenParser*(p: var TParser, filename: string, inputStream: PLLStream) =
|
||||
openParser(p, filename.fileInfoIdx, inputStream)
|
||||
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
||||
strongSpaces=false) =
|
||||
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
|
||||
|
||||
proc CloseParser(p: var TParser) =
|
||||
CloseLexer(p.lex)
|
||||
proc closeParser(p: var TParser) =
|
||||
closeLexer(p.lex)
|
||||
|
||||
proc parMessage(p: TParser, msg: TMsgKind, arg: string = "") =
|
||||
lexMessage(p.lex, msg, arg)
|
||||
@@ -135,16 +138,16 @@ proc expectIdentOrKeyw(p: TParser) =
|
||||
if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
|
||||
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
|
||||
|
||||
proc ExpectIdent(p: TParser) =
|
||||
proc expectIdent(p: TParser) =
|
||||
if p.tok.tokType != tkSymbol:
|
||||
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
|
||||
|
||||
proc Eat(p: var TParser, TokType: TTokType) =
|
||||
if p.tok.TokType == TokType: getTok(p)
|
||||
proc eat(p: var TParser, tokType: TTokType) =
|
||||
if p.tok.tokType == tokType: getTok(p)
|
||||
else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
|
||||
|
||||
proc parLineInfo(p: TParser): TLineInfo =
|
||||
result = getLineInfo(p.lex)
|
||||
result = getLineInfo(p.lex, p.tok)
|
||||
|
||||
proc indAndComment(p: var TParser, n: PNode) =
|
||||
if p.tok.indent > p.currInd:
|
||||
@@ -154,7 +157,7 @@ proc indAndComment(p: var TParser, n: PNode) =
|
||||
skipComment(p, n)
|
||||
|
||||
proc newNodeP(kind: TNodeKind, p: TParser): PNode =
|
||||
result = newNodeI(kind, getLineInfo(p.lex))
|
||||
result = newNodeI(kind, parLineInfo(p))
|
||||
|
||||
proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
@@ -185,40 +188,58 @@ proc relevantOprChar(ident: PIdent): char {.inline.} =
|
||||
if result == '\\' and L > 1:
|
||||
result = ident.s[1]
|
||||
|
||||
proc IsSigilLike(tok: TToken): bool {.inline.} =
|
||||
proc isSigilLike(tok: TToken): bool {.inline.} =
|
||||
result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@'
|
||||
|
||||
proc IsLeftAssociative(tok: TToken): bool {.inline.} =
|
||||
proc isLeftAssociative(tok: TToken): bool {.inline.} =
|
||||
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
|
||||
|
||||
proc getPrecedence(tok: TToken): int =
|
||||
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||
template considerStrongSpaces(x): expr =
|
||||
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
|
||||
|
||||
case tok.tokType
|
||||
of tkOpr:
|
||||
let L = tok.ident.s.len
|
||||
let relevantChar = relevantOprChar(tok.ident)
|
||||
|
||||
template considerAsgn(value: expr) =
|
||||
result = if tok.ident.s[L-1] == '=': 1 else: value
|
||||
template considerAsgn(value: expr) =
|
||||
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
|
||||
|
||||
case relevantChar
|
||||
of '$', '^': considerAsgn(10)
|
||||
of '*', '%', '/', '\\': considerAsgn(9)
|
||||
of '~': result = 8
|
||||
of '~': result = considerStrongSpaces(8)
|
||||
of '+', '-', '|': considerAsgn(8)
|
||||
of '&': considerAsgn(7)
|
||||
of '=', '<', '>', '!': result = 5
|
||||
of '=', '<', '>', '!': result = considerStrongSpaces(5)
|
||||
of '.': considerAsgn(6)
|
||||
of '?': result = 2
|
||||
of '?': result = considerStrongSpaces(2)
|
||||
else: considerAsgn(2)
|
||||
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
||||
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
|
||||
of tkDotDot: result = 6
|
||||
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
|
||||
of tkDotDot: result = considerStrongSpaces(6)
|
||||
of tkAnd: result = 4
|
||||
of tkOr, tkXor: result = 3
|
||||
else: result = - 10
|
||||
|
||||
proc isOperator(tok: TToken): bool =
|
||||
result = getPrecedence(tok) >= 0
|
||||
of tkOr, tkXor, tkPtr, tkRef: result = 3
|
||||
else: result = -10
|
||||
|
||||
proc isOperator(tok: TToken): bool =
|
||||
tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
|
||||
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
|
||||
|
||||
proc isUnary(p: TParser): bool =
|
||||
p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and
|
||||
p.tok.strongSpaceB == 0 and
|
||||
p.tok.strongSpaceA > 0
|
||||
|
||||
proc checkBinary(p: TParser) {.inline.} =
|
||||
# we don't check '..' here as that's too annoying
|
||||
if p.strongSpaces and p.tok.tokType == tkOpr:
|
||||
if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB:
|
||||
parMessage(p, errGenerated, "number of spaces around '$#' not consistent"%
|
||||
prettyTok(p.tok))
|
||||
elif p.tok.strongSpaceA notin {0,1,2,4,8}:
|
||||
parMessage(p, errGenerated, "number of spaces must be 0,1,2,4 or 8")
|
||||
|
||||
#| module = stmt ^* (';' / IND{=})
|
||||
#|
|
||||
@@ -252,7 +273,7 @@ proc colcom(p: var TParser, n: PNode) =
|
||||
eat(p, tkColon)
|
||||
skipComment(p, n)
|
||||
|
||||
proc parseSymbol(p: var TParser): PNode =
|
||||
proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||
#| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
|
||||
#| | IDENT
|
||||
case p.tok.tokType
|
||||
@@ -279,7 +300,7 @@ proc parseSymbol(p: var TParser): PNode =
|
||||
add(result, newIdentNodeP(getIdent"{}", p))
|
||||
getTok(p)
|
||||
eat(p, tkCurlyRi)
|
||||
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDotDot:
|
||||
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot:
|
||||
add(result, newIdentNodeP(p.tok.ident, p))
|
||||
getTok(p)
|
||||
of tkIntLit..tkCharLit:
|
||||
@@ -291,9 +312,13 @@ proc parseSymbol(p: var TParser): PNode =
|
||||
break
|
||||
eat(p, tkAccent)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
|
||||
result = ast.emptyNode
|
||||
if allowNil and p.tok.tokType == tkNil:
|
||||
result = newNodeP(nkNilLit, p)
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
|
||||
result = ast.emptyNode
|
||||
|
||||
proc indexExpr(p: var TParser): PNode =
|
||||
#| indexExpr = expr
|
||||
@@ -350,7 +375,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
||||
|
||||
proc dotExpr(p: var TParser, a: PNode): PNode =
|
||||
#| dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
|
||||
var info = p.lex.getlineInfo
|
||||
var info = p.parLineInfo
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
case p.tok.tokType
|
||||
@@ -427,7 +452,7 @@ proc parseCast(p: var TParser): PNode =
|
||||
|
||||
proc setBaseFlags(n: PNode, base: TNumericalBase) =
|
||||
case base
|
||||
of base10: nil
|
||||
of base10: discard
|
||||
of base2: incl(n.flags, nfBase2)
|
||||
of base8: incl(n.flags, nfBase8)
|
||||
of base16: incl(n.flags, nfBase16)
|
||||
@@ -454,11 +479,13 @@ proc complexOrSimpleStmt(p: var TParser): PNode
|
||||
proc simpleExpr(p: var TParser, mode = pmNormal): PNode
|
||||
|
||||
proc semiStmtList(p: var TParser, result: PNode) =
|
||||
inc p.inSemiStmtList
|
||||
result.add(complexOrSimpleStmt(p))
|
||||
while p.tok.tokType == tkSemicolon:
|
||||
while p.tok.tokType == tkSemiColon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(complexOrSimpleStmt(p))
|
||||
dec p.inSemiStmtList
|
||||
result.kind = nkStmtListExpr
|
||||
|
||||
proc parsePar(p: var TParser): PNode =
|
||||
@@ -482,7 +509,7 @@ proc parsePar(p: var TParser): PNode =
|
||||
# XXX 'bind' used to be an expression, so we exclude it here;
|
||||
# tests/reject/tbind2 fails otherwise.
|
||||
semiStmtList(p, result)
|
||||
elif p.tok.tokType == tkSemicolon:
|
||||
elif p.tok.tokType == tkSemiColon:
|
||||
# '(;' enforces 'stmt' context:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
@@ -498,7 +525,9 @@ proc parsePar(p: var TParser): PNode =
|
||||
asgn.sons[0] = a
|
||||
asgn.sons[1] = b
|
||||
result.add(asgn)
|
||||
elif p.tok.tokType == tkSemicolon:
|
||||
if p.tok.tokType == tkSemiColon:
|
||||
semiStmtList(p, result)
|
||||
elif p.tok.tokType == tkSemiColon:
|
||||
# stmt context:
|
||||
result.add(a)
|
||||
semiStmtList(p, result)
|
||||
@@ -518,14 +547,14 @@ proc parsePar(p: var TParser): PNode =
|
||||
eat(p, tkParRi)
|
||||
|
||||
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||
#| | CHAR_LIT
|
||||
#| | NIL
|
||||
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||
#| identOrLiteral = generalizedLit | symbol
|
||||
#| | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||
#| | CHAR_LIT
|
||||
#| | NIL
|
||||
#| identOrLiteral = generalizedLit | symbol | literal
|
||||
#| | par | arrayConstr | setOrTableConstr
|
||||
#| | castExpr
|
||||
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||
@@ -627,20 +656,28 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
getTok(p) # we must consume a token here to prevend endless loops!
|
||||
result = ast.emptyNode
|
||||
|
||||
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||
proc namedParams(p: var TParser, callee: PNode,
|
||||
kind: TNodeKind, endTok: TTokType): PNode =
|
||||
let a = callee
|
||||
result = newNodeP(kind, p)
|
||||
addSon(result, a)
|
||||
exprColonEqExprListAux(p, endTok, result)
|
||||
|
||||
proc parseMacroColon(p: var TParser, x: PNode): PNode
|
||||
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
#| | doBlocks
|
||||
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
||||
#| | '[' optInd indexExprList optPar ']'
|
||||
#| | '{' optInd indexExprList optPar '}'
|
||||
#| | &( '`'|IDENT|literal|'cast') expr # command syntax
|
||||
result = r
|
||||
while p.tok.indent < 0:
|
||||
while p.tok.indent < 0 or
|
||||
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
|
||||
case p.tok.tokType
|
||||
of tkParLe:
|
||||
var a = result
|
||||
result = newNodeP(nkCall, p)
|
||||
addSon(result, a)
|
||||
exprColonEqExprListAux(p, tkParRi, result)
|
||||
of tkParLe:
|
||||
if p.strongSpaces and p.tok.strongSpaceA > 0: break
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
|
||||
result.kind = nkObjConstr
|
||||
else:
|
||||
@@ -653,22 +690,48 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||
of tkDot:
|
||||
result = dotExpr(p, result)
|
||||
result = parseGStrLit(p, result)
|
||||
of tkBracketLe:
|
||||
result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
|
||||
of tkBracketLe:
|
||||
if p.strongSpaces and p.tok.strongSpaceA > 0: break
|
||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||
of tkCurlyLe:
|
||||
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
else: break
|
||||
|
||||
if p.strongSpaces and p.tok.strongSpaceA > 0: break
|
||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
|
||||
if p.inPragma == 0:
|
||||
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
|
||||
# solution, but pragmas.nim can't handle that
|
||||
let a = result
|
||||
result = newNodeP(nkCommand, p)
|
||||
addSon(result, a)
|
||||
addSon result, parseExpr(p)
|
||||
when false:
|
||||
while p.tok.tokType != tkEof:
|
||||
let a = parseExpr(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
if p.tok.tokType == tkDo:
|
||||
parseDoBlocks(p, result)
|
||||
else:
|
||||
result = parseMacroColon(p, result)
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
|
||||
|
||||
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||
result = primary(p, mode)
|
||||
proc parseOperators(p: var TParser, headNode: PNode,
|
||||
limit: int, mode: TPrimaryMode): PNode =
|
||||
result = headNode
|
||||
# expand while operators have priorities higher than 'limit'
|
||||
var opPrec = getPrecedence(p.tok)
|
||||
var opPrec = getPrecedence(p.tok, p.strongSpaces)
|
||||
let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
|
||||
# the operator itself must not start on a new line:
|
||||
while opPrec >= limit and p.tok.indent < 0:
|
||||
var leftAssoc = ord(IsLeftAssociative(p.tok))
|
||||
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
|
||||
checkBinary(p)
|
||||
var leftAssoc = ord(isLeftAssociative(p.tok))
|
||||
var a = newNodeP(nkInfix, p)
|
||||
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
|
||||
getTok(p)
|
||||
@@ -679,7 +742,11 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||
addSon(a, result)
|
||||
addSon(a, b)
|
||||
result = a
|
||||
opPrec = getPrecedence(p.tok)
|
||||
opPrec = getPrecedence(p.tok, p.strongSpaces)
|
||||
|
||||
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||
result = primary(p, mode)
|
||||
result = parseOperators(p, result, limit, mode)
|
||||
|
||||
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
|
||||
result = simpleExprAux(p, -1, mode)
|
||||
@@ -709,6 +776,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
||||
proc parsePragma(p: var TParser): PNode =
|
||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||
result = newNodeP(nkPragma, p)
|
||||
inc p.inPragma
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
||||
@@ -720,6 +788,7 @@ proc parsePragma(p: var TParser): PNode =
|
||||
optPar(p)
|
||||
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
||||
else: parMessage(p, errTokenExpected, ".}")
|
||||
dec p.inPragma
|
||||
|
||||
proc identVis(p: var TParser): PNode =
|
||||
#| identVis = symbol opr? # postfix position
|
||||
@@ -794,7 +863,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||
var a = parseIdentColonEquals(p, {})
|
||||
addSon(result, a)
|
||||
if p.tok.tokType notin {tkComma, tkSemicolon}: break
|
||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||
getTok(p)
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
@@ -836,13 +905,13 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||
parMessage(p, errTokenExpected, ")")
|
||||
break
|
||||
addSon(result, a)
|
||||
if p.tok.tokType notin {tkComma, tkSemicolon}: break
|
||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||
getTok(p)
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
let hasRet = if retColon: p.tok.tokType == tkColon
|
||||
else: p.tok.tokType == tkOpr and IdentEq(p.tok.ident, "->")
|
||||
else: p.tok.tokType == tkOpr and identEq(p.tok.ident, "->")
|
||||
if hasRet and p.tok.indent < 0:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
@@ -898,17 +967,33 @@ proc isExprStart(p: TParser): bool =
|
||||
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
|
||||
tkProc, tkIterator, tkBind, tkAddr,
|
||||
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
|
||||
tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared:
|
||||
tkTuple, tkObject, tkType, tkWhen, tkCase:
|
||||
result = true
|
||||
else: result = false
|
||||
|
||||
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
|
||||
mode: TPrimaryMode): PNode =
|
||||
|
||||
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
|
||||
while true:
|
||||
var s = parseSymbol(p, allowNil)
|
||||
if s.kind == nkEmpty: break
|
||||
addSon(result, s)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, s)
|
||||
|
||||
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
|
||||
mode: TPrimaryMode): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
if not isOperator(p.tok) and isExprStart(p):
|
||||
addSon(result, primary(p, mode))
|
||||
if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}:
|
||||
let nodeKind = if p.tok.tokType == tkWith: nkWith
|
||||
else: nkWithout
|
||||
getTok(p)
|
||||
let list = newNodeP(nodeKind, p)
|
||||
result.addSon list
|
||||
parseSymbolList(p, list, allowNil = true)
|
||||
|
||||
proc parseExpr(p: var TParser): PNode =
|
||||
#| expr = (ifExpr
|
||||
@@ -923,9 +1008,9 @@ proc parseExpr(p: var TParser): PNode =
|
||||
of tkTry: result = parseTry(p)
|
||||
else: result = simpleExpr(p)
|
||||
|
||||
proc parseObject(p: var TParser): PNode
|
||||
proc parseDistinct(p: var TParser): PNode
|
||||
proc parseEnum(p: var TParser): PNode
|
||||
proc parseObject(p: var TParser): PNode
|
||||
proc parseTypeClass(p: var TParser): PNode
|
||||
|
||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
#| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
|
||||
@@ -936,7 +1021,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
#| / 'static' primary
|
||||
#| / 'bind' primary
|
||||
if isOperator(p.tok):
|
||||
let isSigil = IsSigilLike(p.tok)
|
||||
let isSigil = isSigilLike(p.tok)
|
||||
result = newNodeP(nkPrefix, p)
|
||||
var a = newIdentNodeP(p.tok.ident, p)
|
||||
addSon(result, a)
|
||||
@@ -944,8 +1029,9 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
optInd(p, a)
|
||||
if isSigil:
|
||||
#XXX prefix operators
|
||||
let baseInd = p.lex.currLineIndent
|
||||
addSon(result, primary(p, pmSkipSuffix))
|
||||
result = primarySuffix(p, result)
|
||||
result = primarySuffix(p, result, baseInd)
|
||||
else:
|
||||
addSon(result, primary(p, pmNormal))
|
||||
return
|
||||
@@ -954,19 +1040,24 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
|
||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
|
||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
||||
of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode)
|
||||
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
|
||||
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
|
||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||
of tkIterator:
|
||||
if mode in {pmTypeDesc, pmTypeDef}:
|
||||
result = parseProcExpr(p, false)
|
||||
result.kind = nkIteratorTy
|
||||
when false:
|
||||
if mode in {pmTypeDesc, pmTypeDef}:
|
||||
result = parseProcExpr(p, false)
|
||||
result.kind = nkIteratorTy
|
||||
else:
|
||||
# no anon iterators for now:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p) # we must consume a token here to prevend endless loops!
|
||||
result = ast.emptyNode
|
||||
else:
|
||||
# no anon iterators for now:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p) # we must consume a token here to prevend endless loops!
|
||||
result = ast.emptyNode
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||
if result.kind == nkLambda: result.kind = nkIteratorDef
|
||||
else: result.kind = nkIteratorTy
|
||||
of tkEnum:
|
||||
if mode == pmTypeDef:
|
||||
result = parseEnum(p)
|
||||
@@ -979,29 +1070,33 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
else:
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkDistinct:
|
||||
of tkGeneric:
|
||||
if mode == pmTypeDef:
|
||||
result = parseDistinct(p)
|
||||
result = parseTypeClass(p)
|
||||
else:
|
||||
result = newNodeP(nkDistinctTy, p)
|
||||
getTok(p)
|
||||
parMessage(p, errInvalidToken, p.tok)
|
||||
of tkAddr:
|
||||
result = newNodeP(nkAddr, p)
|
||||
getTokNoInd(p)
|
||||
addSon(result, primary(p, pmNormal))
|
||||
of tkStatic:
|
||||
result = newNodeP(nkStaticExpr, p)
|
||||
let info = parLineInfo(p)
|
||||
getTokNoInd(p)
|
||||
addSon(result, primary(p, pmNormal))
|
||||
let next = primary(p, pmNormal)
|
||||
if next.kind == nkBracket and next.sonsLen == 1:
|
||||
result = newNode(nkStaticTy, info, @[next.sons[0]])
|
||||
else:
|
||||
result = newNode(nkStaticExpr, info, @[next])
|
||||
of tkBind:
|
||||
result = newNodeP(nkBind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, primary(p, pmNormal))
|
||||
else:
|
||||
let baseInd = p.lex.currLineIndent
|
||||
result = identOrLiteral(p, mode)
|
||||
if mode != pmSkipSuffix:
|
||||
result = primarySuffix(p, result)
|
||||
result = primarySuffix(p, result, baseInd)
|
||||
|
||||
proc parseTypeDesc(p: var TParser): PNode =
|
||||
#| typeDesc = simpleExpr
|
||||
@@ -1009,6 +1104,7 @@ proc parseTypeDesc(p: var TParser): PNode =
|
||||
|
||||
proc parseTypeDefAux(p: var TParser): PNode =
|
||||
#| typeDefAux = simpleExpr
|
||||
#| | 'generic' typeClass
|
||||
result = simpleExpr(p, pmTypeDef)
|
||||
|
||||
proc makeCall(n: PNode): PNode =
|
||||
@@ -1018,17 +1114,54 @@ proc makeCall(n: PNode): PNode =
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add n
|
||||
|
||||
proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' exprList ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
result = x
|
||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||
result = makeCall(result)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
addSon(result, newProcNode(nkDo, body.info, body))
|
||||
while sameInd(p):
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
of tkOf:
|
||||
b = newNodeP(nkOfBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
of tkElif:
|
||||
b = newNodeP(nkElifBranch, p)
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
addSon(b, parseExpr(p))
|
||||
eat(p, tkColon)
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
skipComment(p, b)
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
else: break
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
if b.kind == nkElse: break
|
||||
|
||||
proc parseExprStmt(p: var TParser): PNode =
|
||||
#| exprStmt = simpleExpr
|
||||
#| (( '=' optInd expr )
|
||||
#| / ( expr ^+ comma
|
||||
#| doBlocks
|
||||
#| / ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' exprList ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
#| / macroColon
|
||||
#| ))?
|
||||
inc p.inPragma
|
||||
var a = simpleExpr(p)
|
||||
dec p.inPragma
|
||||
if p.tok.tokType == tkEquals:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
@@ -1051,37 +1184,18 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||
result = makeCall(result)
|
||||
parseDoBlocks(p, result)
|
||||
return result
|
||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||
result = makeCall(result)
|
||||
result = parseMacroColon(p, result)
|
||||
|
||||
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
||||
result = parseExpr(p)
|
||||
when false:
|
||||
# parseExpr already handles 'as' syntax ...
|
||||
if p.tok.tokType == tkAs and kind == nkImportStmt:
|
||||
let a = result
|
||||
result = newNodeP(nkImportAs, p)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
addSon(result, newProcNode(nkDo, body.info, body))
|
||||
while sameInd(p):
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
of tkOf:
|
||||
b = newNodeP(nkOfBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
of tkElif:
|
||||
b = newNodeP(nkElifBranch, p)
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
addSon(b, parseExpr(p))
|
||||
eat(p, tkColon)
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
skipComment(p, b)
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
else: break
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
if b.kind == nkElse: break
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
|
||||
proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| importStmt = 'import' optInd expr
|
||||
@@ -1090,7 +1204,7 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p) # skip `import` or `export`
|
||||
optInd(p, result)
|
||||
var a = parseExpr(p)
|
||||
var a = parseModuleName(p, kind)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType in {tkComma, tkExcept}:
|
||||
if p.tok.tokType == tkExcept:
|
||||
@@ -1099,10 +1213,10 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
|
||||
optInd(p, result)
|
||||
while true:
|
||||
# was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
|
||||
a = parseExpr(p)
|
||||
if a.kind == nkEmpty: break
|
||||
a = parseModuleName(p, kind)
|
||||
if a.kind == nkEmpty: break
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
#expectNl(p)
|
||||
@@ -1123,11 +1237,11 @@ proc parseIncludeStmt(p: var TParser): PNode =
|
||||
#expectNl(p)
|
||||
|
||||
proc parseFromStmt(p: var TParser): PNode =
|
||||
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
|
||||
#| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
|
||||
result = newNodeP(nkFromStmt, p)
|
||||
getTok(p) # skip `from`
|
||||
optInd(p, result)
|
||||
var a = parseExpr(p)
|
||||
var a = parseModuleName(p, nkImportStmt)
|
||||
addSon(result, a) #optInd(p, a);
|
||||
eat(p, tkImport)
|
||||
optInd(p, result)
|
||||
@@ -1153,8 +1267,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
|
||||
if p.tok.tokType == tkComment:
|
||||
skipComment(p, result)
|
||||
addSon(result, ast.emptyNode)
|
||||
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or
|
||||
p.tok.tokType == tkEof:
|
||||
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
|
||||
# NL terminates:
|
||||
addSon(result, ast.emptyNode)
|
||||
else:
|
||||
@@ -1362,7 +1475,7 @@ proc parseGenericParamList(p: var TParser): PNode =
|
||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||
var a = parseGenericParam(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType notin {tkComma, tkSemicolon}: break
|
||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||
getTok(p)
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
@@ -1407,7 +1520,6 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
|
||||
proc newCommentStmt(p: var TParser): PNode =
|
||||
#| commentStmt = COMMENT
|
||||
result = newNodeP(nkCommentStmt, p)
|
||||
result.info.line = result.info.line - int16(1) - int16(p.tok.iNumber)
|
||||
result.comment = p.tok.literal
|
||||
getTok(p)
|
||||
|
||||
@@ -1418,14 +1530,14 @@ proc parseSection(p: var TParser, kind: TNodeKind,
|
||||
defparser: TDefParser): PNode =
|
||||
#| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
if kind != nkTypeSection: getTok(p)
|
||||
skipComment(p, result)
|
||||
if realInd(p):
|
||||
withInd(p):
|
||||
skipComment(p, result)
|
||||
while sameInd(p):
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent:
|
||||
of tkSymbol, tkAccent, tkParLe:
|
||||
var a = defparser(p)
|
||||
skipComment(p, a)
|
||||
addSon(result, a)
|
||||
@@ -1609,12 +1721,47 @@ proc parseObject(p: var TParser): PNode =
|
||||
return
|
||||
addSon(result, parseObjectPart(p))
|
||||
|
||||
proc parseDistinct(p: var TParser): PNode =
|
||||
#| distinct = 'distinct' optInd typeDesc
|
||||
result = newNodeP(nkDistinctTy, p)
|
||||
proc parseTypeClassParam(p: var TParser): PNode =
|
||||
if p.tok.tokType == tkVar:
|
||||
getTok(p)
|
||||
result = newNode(nkVarTy)
|
||||
result.addSon(p.parseSymbol)
|
||||
else:
|
||||
result = p.parseSymbol
|
||||
|
||||
proc parseTypeClass(p: var TParser): PNode =
|
||||
#| typeClassParam = ('var')? symbol
|
||||
#| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||
#| &IND{>} stmt
|
||||
result = newNodeP(nkTypeClassTy, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, parseTypeDesc(p))
|
||||
var args = newNode(nkArgList)
|
||||
addSon(result, args)
|
||||
addSon(args, p.parseTypeClassParam)
|
||||
while p.tok.tokType == tkComma:
|
||||
getTok(p)
|
||||
addSon(args, p.parseTypeClassParam)
|
||||
if p.tok.tokType == tkCurlyDotLe and p.validInd:
|
||||
addSon(result, parsePragma(p))
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
if p.tok.tokType == tkOf and p.tok.indent < 0:
|
||||
var a = newNodeP(nkOfInherit, p)
|
||||
getTok(p)
|
||||
while true:
|
||||
addSon(a, parseTypeDesc(p))
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
addSon(result, a)
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
if p.tok.tokType == tkComment:
|
||||
skipComment(p, result)
|
||||
# an initial IND{>} HAS to follow:
|
||||
if not realInd(p):
|
||||
addSon(result, emptyNode)
|
||||
else:
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseTypeDef(p: var TParser): PNode =
|
||||
#| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
|
||||
@@ -1737,31 +1884,43 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||
of tkMacro: result = parseRoutine(p, nkMacroDef)
|
||||
of tkTemplate: result = parseRoutine(p, nkTemplateDef)
|
||||
of tkConverter: result = parseRoutine(p, nkConverterDef)
|
||||
of tkType: result = parseSection(p, nkTypeSection, parseTypeDef)
|
||||
of tkType:
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkParLe:
|
||||
getTok(p)
|
||||
result = newNodeP(nkTypeOfExpr, p)
|
||||
result.addSon(primary(p, pmTypeDesc))
|
||||
eat(p, tkParRi)
|
||||
result = parseOperators(p, result, -1, pmNormal)
|
||||
else:
|
||||
result = parseSection(p, nkTypeSection, parseTypeDef)
|
||||
of tkConst: result = parseSection(p, nkConstSection, parseConstant)
|
||||
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
|
||||
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
|
||||
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
||||
of tkBind: result = parseBind(p, nkBindStmt)
|
||||
of tkMixin: result = parseBind(p, nkMixinStmt)
|
||||
of tkUsing: result = parseBind(p, nkUsingStmt)
|
||||
else: result = simpleStmt(p)
|
||||
|
||||
proc parseStmt(p: var TParser): PNode =
|
||||
#| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
|
||||
#| / simpleStmt
|
||||
#| / simpleStmt ^+ ';'
|
||||
if p.tok.indent > p.currInd:
|
||||
result = newNodeP(nkStmtList, p)
|
||||
withInd(p):
|
||||
while true:
|
||||
if p.tok.indent == p.currInd:
|
||||
nil
|
||||
elif p.tok.tokType == tkSemicolon:
|
||||
while p.tok.tokType == tkSemicolon: getTok(p)
|
||||
discard
|
||||
elif p.tok.tokType == tkSemiColon:
|
||||
getTok(p)
|
||||
if p.tok.indent < 0 or p.tok.indent == p.currInd: discard
|
||||
else: break
|
||||
else:
|
||||
if p.tok.indent > p.currInd:
|
||||
if p.tok.indent > p.currInd and p.tok.tokType != tkDot:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
break
|
||||
if p.tok.toktype in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
|
||||
if p.tok.tokType in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
|
||||
# XXX this ensures tnamedparamanonproc still compiles;
|
||||
# deprecate this syntax later
|
||||
break
|
||||
@@ -1779,10 +1938,19 @@ proc parseStmt(p: var TParser): PNode =
|
||||
parMessage(p, errComplexStmtRequiresInd)
|
||||
result = ast.emptyNode
|
||||
else:
|
||||
if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)
|
||||
result = simpleStmt(p)
|
||||
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||
#while p.tok.tokType == tkSemicolon: getTok(p)
|
||||
if p.inSemiStmtList > 0:
|
||||
result = simpleStmt(p)
|
||||
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||
else:
|
||||
result = newNodeP(nkStmtList, p)
|
||||
while true:
|
||||
if p.tok.indent >= 0:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
let a = simpleStmt(p)
|
||||
if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||
result.add(a)
|
||||
if p.tok.tokType != tkSemiColon: break
|
||||
getTok(p)
|
||||
|
||||
proc parseAll(p: var TParser): PNode =
|
||||
result = newNodeP(nkStmtList, p)
|
||||
@@ -1801,11 +1969,14 @@ proc parseTopLevelStmt(p: var TParser): PNode =
|
||||
result = ast.emptyNode
|
||||
while true:
|
||||
if p.tok.indent != 0:
|
||||
if p.firstTok and p.tok.indent < 0: nil
|
||||
if p.firstTok and p.tok.indent < 0: discard
|
||||
else: parMessage(p, errInvalidIndentation)
|
||||
p.firstTok = false
|
||||
case p.tok.tokType
|
||||
of tkSemicolon: getTok(p)
|
||||
of tkSemiColon:
|
||||
getTok(p)
|
||||
if p.tok.indent <= 0: discard
|
||||
else: parMessage(p, errInvalidIndentation)
|
||||
of tkEof: break
|
||||
else:
|
||||
result = complexOrSimpleStmt(p)
|
||||
@@ -1813,11 +1984,13 @@ proc parseTopLevelStmt(p: var TParser): PNode =
|
||||
break
|
||||
|
||||
proc parseString(s: string, filename: string = "", line: int = 0): PNode =
|
||||
var stream = LLStreamOpen(s)
|
||||
var stream = llStreamOpen(s)
|
||||
stream.lineOffset = line
|
||||
|
||||
var parser: TParser
|
||||
OpenParser(parser, filename, stream)
|
||||
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
|
||||
# spaces...
|
||||
openParser(parser, filename, stream, false)
|
||||
|
||||
result = parser.parseAll
|
||||
CloseParser(parser)
|
||||
closeParser(parser)
|
||||
|
||||
@@ -26,7 +26,7 @@ Options:
|
||||
"""
|
||||
|
||||
proc main(infile, outfile: string, flags: set[TParserFlag]) =
|
||||
var stream = LLStreamOpen(infile, fmRead)
|
||||
var stream = llStreamOpen(infile, fmRead)
|
||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
||||
var p: TParser
|
||||
openParser(p, infile, stream, flags)
|
||||
|
||||
@@ -78,7 +78,7 @@ type
|
||||
|
||||
|
||||
proc getTok*(L: var TLexer, tok: var TToken)
|
||||
proc PrintTok*(tok: TToken)
|
||||
proc printTok*(tok: TToken)
|
||||
proc `$`*(tok: TToken): string
|
||||
# implementation
|
||||
|
||||
@@ -109,17 +109,17 @@ proc getLineInfo*(L: TLexer): TLineInfo =
|
||||
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
|
||||
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
msgs.GlobalError(getLineInfo(L), msg, arg)
|
||||
msgs.globalError(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
|
||||
msgs.GlobalError(info, msg, arg)
|
||||
msgs.globalError(info, msg, arg)
|
||||
|
||||
proc TokKindToStr*(k: TTokKind): string =
|
||||
proc tokKindToStr*(k: TTokKind): string =
|
||||
case k
|
||||
of pxEof: result = "[EOF]"
|
||||
of firstKeyword..lastKeyword:
|
||||
result = keywords[ord(k)-ord(firstKeyword)]
|
||||
result = Keywords[ord(k)-ord(firstKeyword)]
|
||||
of pxInvalid, pxComment, pxStrLit: result = "string literal"
|
||||
of pxCommand: result = "{@"
|
||||
of pxAmp: result = "{&"
|
||||
@@ -160,9 +160,9 @@ proc `$`(tok: TToken): string =
|
||||
of pxSymbol: result = tok.ident.s
|
||||
of pxIntLit, pxInt64Lit: result = $tok.iNumber
|
||||
of pxFloatLit: result = $tok.fNumber
|
||||
else: result = TokKindToStr(tok.xkind)
|
||||
else: result = tokKindToStr(tok.xkind)
|
||||
|
||||
proc PrintTok(tok: TToken) =
|
||||
proc printTok(tok: TToken) =
|
||||
writeln(stdout, $tok)
|
||||
|
||||
proc setKeyword(L: var TLexer, tok: var TToken) =
|
||||
@@ -177,12 +177,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.literal, buf[pos])
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
add(tok.literal, '_')
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
L.bufPos = pos
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
@@ -199,7 +199,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos)
|
||||
return
|
||||
tok.base = base2
|
||||
var xi: biggestInt = 0
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -221,7 +221,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1 # skip $
|
||||
tok.base = base16
|
||||
var xi: biggestInt = 0
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -261,7 +261,7 @@ proc getNumber10(L: var TLexer, tok: var TToken) =
|
||||
tok.fnumber = parseFloat(tok.literal)
|
||||
tok.xkind = pxFloatLit
|
||||
else:
|
||||
tok.iNumber = ParseInt(tok.literal)
|
||||
tok.iNumber = parseInt(tok.literal)
|
||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
||||
tok.xkind = pxInt64Lit
|
||||
else:
|
||||
@@ -271,10 +271,10 @@ proc getNumber10(L: var TLexer, tok: var TToken) =
|
||||
except EOverflow:
|
||||
lexMessage(L, errNumberOutOfRange, tok.literal)
|
||||
|
||||
proc HandleCRLF(L: var TLexer, pos: int): int =
|
||||
proc handleCRLF(L: var TLexer, pos: int): int =
|
||||
case L.buf[pos]
|
||||
of CR: result = nimlexbase.HandleCR(L, pos)
|
||||
of LF: result = nimlexbase.HandleLF(L, pos)
|
||||
of CR: result = nimlexbase.handleCR(L, pos)
|
||||
of LF: result = nimlexbase.handleLF(L, pos)
|
||||
else: result = pos
|
||||
|
||||
proc getString(L: var TLexer, tok: var TToken) =
|
||||
@@ -319,7 +319,7 @@ proc getString(L: var TLexer, tok: var TToken) =
|
||||
xi = (xi * 10) + (ord(buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
else: lexMessage(L, errInvalidCharacterConstant)
|
||||
if (xi <= 255): add(tok.literal, Chr(xi))
|
||||
if (xi <= 255): add(tok.literal, chr(xi))
|
||||
else: lexMessage(L, errInvalidCharacterConstant)
|
||||
else:
|
||||
break
|
||||
@@ -334,17 +334,17 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var c = buf[pos]
|
||||
case c
|
||||
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
|
||||
h = h +% Ord(c)
|
||||
h = h +% ord(c)
|
||||
h = h +% h shl 10
|
||||
h = h xor (h shr 6)
|
||||
of 'A'..'Z':
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h +% Ord(c)
|
||||
h = h +% ord(c)
|
||||
h = h +% h shl 10
|
||||
h = h xor (h shr 6)
|
||||
of '_': nil
|
||||
of '_': discard
|
||||
else: break
|
||||
Inc(pos)
|
||||
inc(pos)
|
||||
h = h +% h shl 3
|
||||
h = h xor (h shr 11)
|
||||
h = h +% h shl 15
|
||||
@@ -385,7 +385,7 @@ proc scanCurlyComment(L: var TLexer, tok: var TToken) =
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.literal, "\n#")
|
||||
of '}':
|
||||
@@ -405,7 +405,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.literal, "\n#")
|
||||
of '*':
|
||||
@@ -428,9 +428,9 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||
while true:
|
||||
case buf[pos]
|
||||
of ' ', Tabulator:
|
||||
Inc(pos) # newline is special:
|
||||
inc(pos) # newline is special:
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
@@ -449,7 +449,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
case c
|
||||
of ';':
|
||||
tok.xkind = pxSemicolon
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '/':
|
||||
if L.buf[L.bufpos + 1] == '/':
|
||||
scanLineComment(L, tok)
|
||||
@@ -458,12 +458,12 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos)
|
||||
of ',':
|
||||
tok.xkind = pxComma
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '(':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
if (L.buf[L.bufPos] == '*'):
|
||||
if (L.buf[L.bufPos + 1] == '$'):
|
||||
Inc(L.bufpos, 2)
|
||||
inc(L.bufpos, 2)
|
||||
skip(L, tok)
|
||||
getSymbol(L, tok)
|
||||
tok.xkind = pxStarDirLe
|
||||
@@ -481,12 +481,12 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
tok.xkind = pxStar
|
||||
of ')':
|
||||
tok.xkind = pxParRi
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '[':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketLe
|
||||
of ']':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketRi
|
||||
of '.':
|
||||
inc(L.bufpos)
|
||||
@@ -496,21 +496,21 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
else:
|
||||
tok.xkind = pxDot
|
||||
of '{':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
case L.buf[L.bufpos]
|
||||
of '$':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
skip(L, tok)
|
||||
getSymbol(L, tok)
|
||||
tok.xkind = pxCurlyDirLe
|
||||
of '&':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxAmp
|
||||
of '%':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxPer
|
||||
of '@':
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxCommand
|
||||
else: scanCurlyComment(L, tok)
|
||||
of '+':
|
||||
@@ -554,7 +554,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos)
|
||||
of '}':
|
||||
tok.xkind = pxCurlyDirRi
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
of '\'', '#':
|
||||
getString(L, tok)
|
||||
of '$':
|
||||
@@ -567,4 +567,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||
tok.literal = c & ""
|
||||
tok.xkind = pxInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
Inc(L.bufpos)
|
||||
inc(L.bufpos)
|
||||
|
||||
@@ -57,7 +57,7 @@ const
|
||||
["tbinaryfile", "tfile"], ["strstart", "0"], ["nl", "\"\\n\""],
|
||||
["tostring", "$"]]
|
||||
|
||||
proc ParseUnit*(p: var TParser): PNode
|
||||
proc parseUnit*(p: var TParser): PNode
|
||||
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
||||
flags: set[TParserFlag] = {})
|
||||
proc closeParser*(p: var TParser)
|
||||
@@ -67,20 +67,20 @@ proc fixRecordDef*(n: var PNode)
|
||||
|
||||
# implementation
|
||||
|
||||
proc OpenParser(p: var TParser, filename: string,
|
||||
proc openParser(p: var TParser, filename: string,
|
||||
inputStream: PLLStream, flags: set[TParserFlag] = {}) =
|
||||
OpenLexer(p.lex, filename, inputStream)
|
||||
openLexer(p.lex, filename, inputStream)
|
||||
initIdTable(p.repl)
|
||||
for i in countup(low(stdReplacements), high(stdReplacements)):
|
||||
IdTablePut(p.repl, getIdent(stdReplacements[i][0]),
|
||||
idTablePut(p.repl, getIdent(stdReplacements[i][0]),
|
||||
getIdent(stdReplacements[i][1]))
|
||||
if pfMoreReplacements in flags:
|
||||
for i in countup(low(nimReplacements), high(nimReplacements)):
|
||||
IdTablePut(p.repl, getIdent(nimReplacements[i][0]),
|
||||
idTablePut(p.repl, getIdent(nimReplacements[i][0]),
|
||||
getIdent(nimReplacements[i][1]))
|
||||
p.flags = flags
|
||||
|
||||
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
|
||||
proc closeParser(p: var TParser) = closeLexer(p.lex)
|
||||
proc getTok(p: var TParser) = getTok(p.lex, p.tok)
|
||||
|
||||
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
|
||||
@@ -98,15 +98,15 @@ proc skipCom(p: var TParser, n: PNode) =
|
||||
parMessage(p, warnCommentXIgnored, p.tok.literal)
|
||||
getTok(p)
|
||||
|
||||
proc ExpectIdent(p: TParser) =
|
||||
proc expectIdent(p: TParser) =
|
||||
if p.tok.xkind != pxSymbol:
|
||||
lexMessage(p.lex, errIdentifierExpected, $(p.tok))
|
||||
|
||||
proc Eat(p: var TParser, xkind: TTokKind) =
|
||||
proc eat(p: var TParser, xkind: TTokKind) =
|
||||
if p.tok.xkind == xkind: getTok(p)
|
||||
else: lexMessage(p.lex, errTokenExpected, TokKindToStr(xkind))
|
||||
else: lexMessage(p.lex, errTokenExpected, tokKindToStr(xkind))
|
||||
|
||||
proc Opt(p: var TParser, xkind: TTokKind) =
|
||||
proc opt(p: var TParser, xkind: TTokKind) =
|
||||
if p.tok.xkind == xkind: getTok(p)
|
||||
|
||||
proc newNodeP(kind: TNodeKind, p: TParser): PNode =
|
||||
@@ -131,7 +131,7 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
|
||||
|
||||
proc createIdentNodeP(ident: PIdent, p: TParser): PNode =
|
||||
result = newNodeP(nkIdent, p)
|
||||
var x = PIdent(IdTableGet(p.repl, ident))
|
||||
var x = PIdent(idTableGet(p.repl, ident))
|
||||
if x != nil: result.ident = x
|
||||
else: result.ident = ident
|
||||
|
||||
@@ -170,7 +170,7 @@ proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
|
||||
getTok(p)
|
||||
eat(p, pxCurlyDirRi)
|
||||
result = parseExpr(p)
|
||||
if result.kind == nkEmpty: InternalError("emptyNode modified")
|
||||
if result.kind == nkEmpty: internalError("emptyNode modified")
|
||||
result.kind = nkCurly
|
||||
elif p.tok.ident.id == getIdent("cast").id:
|
||||
getTok(p)
|
||||
@@ -251,7 +251,7 @@ proc bracketExprList(p: var TParser, first: PNode): PNode =
|
||||
getTok(p)
|
||||
break
|
||||
if p.tok.xkind == pxEof:
|
||||
parMessage(p, errTokenExpected, TokKindToStr(pxBracketRi))
|
||||
parMessage(p, errTokenExpected, tokKindToStr(pxBracketRi))
|
||||
break
|
||||
var a = rangeExpr(p)
|
||||
skipCom(p, a)
|
||||
@@ -281,7 +281,7 @@ proc exprListAux(p: var TParser, elemKind: TNodeKind,
|
||||
getTok(p)
|
||||
break
|
||||
if p.tok.xkind == pxEof:
|
||||
parMessage(p, errTokenExpected, TokKindToStr(endtok))
|
||||
parMessage(p, errTokenExpected, tokKindToStr(endTok))
|
||||
break
|
||||
var a = exprColonEqExpr(p, elemKind, sepTok)
|
||||
skipCom(p, a)
|
||||
@@ -319,7 +319,7 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokKind,
|
||||
getTok(p)
|
||||
break
|
||||
if p.tok.xkind == pxEof:
|
||||
parMessage(p, errTokenExpected, TokKindToStr(endtok))
|
||||
parMessage(p, errTokenExpected, tokKindToStr(endTok))
|
||||
break
|
||||
var a = qualifiedIdent(p)
|
||||
skipCom(p, a)
|
||||
@@ -335,7 +335,7 @@ proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind,
|
||||
|
||||
proc setBaseFlags(n: PNode, base: TNumericalBase) =
|
||||
case base
|
||||
of base10: nil
|
||||
of base10: discard
|
||||
of base2: incl(n.flags, nfBase2)
|
||||
of base8: incl(n.flags, nfBase8)
|
||||
of base16: incl(n.flags, nfBase16)
|
||||
@@ -466,7 +466,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
|
||||
eat(p, pxCurlyDirRi)
|
||||
opNode.ident = getIdent("&")
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
of pxMinus:
|
||||
if p.tok.xkind == pxPer:
|
||||
getTok(p)
|
||||
@@ -477,7 +477,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
|
||||
of pxNeq:
|
||||
opNode.ident = getIdent("!=")
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
skipCom(p, opNode) # read sub-expression with higher priority
|
||||
nextop = lowestExprAux(p, v2, opPred)
|
||||
addSon(node, opNode)
|
||||
@@ -505,7 +505,7 @@ proc fixExpr(n: PNode): PNode =
|
||||
(n.sons[2].kind in {nkCharLit, nkStrLit}):
|
||||
n.sons[0].ident = getIdent("&") # fix operator
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
if not (n.kind in {nkEmpty..nkNilLit}):
|
||||
for i in countup(0, sonsLen(n) - 1): result.sons[i] = fixExpr(n.sons[i])
|
||||
|
||||
@@ -584,7 +584,7 @@ proc parseIncludeDir(p: var TParser): PNode =
|
||||
proc definedExprAux(p: var TParser): PNode =
|
||||
result = newNodeP(nkCall, p)
|
||||
addSon(result, newIdentNodeP(getIdent("defined"), p))
|
||||
ExpectIdent(p)
|
||||
expectIdent(p)
|
||||
addSon(result, createIdentNodeP(p.tok.ident, p))
|
||||
getTok(p)
|
||||
|
||||
@@ -603,7 +603,7 @@ proc parseStmtList(p: var TParser): PNode =
|
||||
of pxCurlyDirLe, pxStarDirLe:
|
||||
if not isHandledDirective(p): break
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
addSon(result, parseStmt(p))
|
||||
if sonsLen(result) == 1: result = result.sons[0]
|
||||
|
||||
@@ -732,7 +732,7 @@ proc parseRepeat(p: var TParser): PNode =
|
||||
addSon(b, c)
|
||||
addSon(a, b)
|
||||
if b.sons[0].kind == nkIdent and b.sons[0].ident.id == getIdent("false").id:
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
addSon(s, a)
|
||||
addSon(result, s)
|
||||
@@ -753,7 +753,7 @@ proc parseCase(p: var TParser): PNode =
|
||||
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxColon):
|
||||
addSon(b, rangeExpr(p))
|
||||
opt(p, pxComma)
|
||||
skipcom(p, b)
|
||||
skipCom(p, b)
|
||||
eat(p, pxColon)
|
||||
skipCom(p, b)
|
||||
addSon(b, parseStmt(p))
|
||||
@@ -818,7 +818,7 @@ proc parseFor(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
b = parseExpr(p)
|
||||
else:
|
||||
parMessage(p, errTokenExpected, TokKindToStr(pxTo))
|
||||
parMessage(p, errTokenExpected, tokKindToStr(pxTo))
|
||||
addSon(c, a)
|
||||
addSon(c, b)
|
||||
eat(p, pxDo)
|
||||
@@ -840,7 +840,7 @@ proc parseParam(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
v = newNodeP(nkVarTy, p)
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
while true:
|
||||
case p.tok.xkind
|
||||
of pxSymbol: a = createIdentNodeP(p.tok.ident, p)
|
||||
@@ -915,7 +915,7 @@ proc parseCallingConvention(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
opt(p, pxSemicolon)
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
|
||||
var e: PNode
|
||||
@@ -1096,7 +1096,7 @@ proc parseRecordCase(p: var TParser): PNode =
|
||||
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxColon):
|
||||
addSon(b, rangeExpr(p))
|
||||
opt(p, pxComma)
|
||||
skipcom(p, b)
|
||||
skipCom(p, b)
|
||||
eat(p, pxColon)
|
||||
skipCom(p, b)
|
||||
c = newNodeP(nkRecList, p)
|
||||
@@ -1133,7 +1133,7 @@ proc parseRecordPart(p: var TParser): PNode =
|
||||
proc exSymbol(n: var PNode) =
|
||||
case n.kind
|
||||
of nkPostfix:
|
||||
nil
|
||||
discard
|
||||
of nkPragmaExpr:
|
||||
exSymbol(n.sons[0])
|
||||
of nkIdent, nkAccQuoted:
|
||||
@@ -1154,7 +1154,7 @@ proc fixRecordDef(n: var PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i])
|
||||
of nkIdentDefs:
|
||||
for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i])
|
||||
of nkNilLit, nkEmpty: nil
|
||||
of nkNilLit, nkEmpty: discard
|
||||
else: internalError(n.info, "fixRecordDef(): " & $n.kind)
|
||||
|
||||
proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
|
||||
@@ -1168,7 +1168,7 @@ proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
|
||||
else:
|
||||
pragmasNode = ident.sons[1]
|
||||
if pragmasNode.kind != nkPragma:
|
||||
InternalError(ident.info, "addPragmaToIdent")
|
||||
internalError(ident.info, "addPragmaToIdent")
|
||||
addSon(pragmasNode, pragma)
|
||||
|
||||
proc parseRecordBody(p: var TParser, result, definition: PNode) =
|
||||
@@ -1183,15 +1183,15 @@ proc parseRecordBody(p: var TParser, result, definition: PNode) =
|
||||
if definition != nil:
|
||||
addPragmaToIdent(definition.sons[0], newIdentNodeP(p.tok.ident, p))
|
||||
else:
|
||||
InternalError(result.info, "anonymous record is not supported")
|
||||
internalError(result.info, "anonymous record is not supported")
|
||||
getTok(p)
|
||||
else:
|
||||
InternalError(result.info, "parseRecordBody")
|
||||
internalError(result.info, "parseRecordBody")
|
||||
of pxCommand:
|
||||
if definition != nil: addPragmaToIdent(definition.sons[0], parseCommand(p))
|
||||
else: InternalError(result.info, "anonymous record is not supported")
|
||||
else: internalError(result.info, "anonymous record is not supported")
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
opt(p, pxSemicolon)
|
||||
skipCom(p, result)
|
||||
|
||||
@@ -1223,7 +1223,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
|
||||
getTok(p)
|
||||
if p.tok.xkind == pxCommand:
|
||||
result = parseCommand(p)
|
||||
if result.kind != nkTupleTy: InternalError(result.info, "parseTypeDesc")
|
||||
if result.kind != nkTupleTy: internalError(result.info, "parseTypeDesc")
|
||||
parseRecordBody(p, result, definition)
|
||||
var a = lastSon(result) # embed nkRecList directly into nkTupleTy
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
@@ -1237,7 +1237,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
|
||||
if definition != nil:
|
||||
addPragmaToIdent(definition.sons[0], newIdentNodeP(getIdent("final"), p))
|
||||
else:
|
||||
InternalError(result.info, "anonymous record is not supported")
|
||||
internalError(result.info, "anonymous record is not supported")
|
||||
of pxObject: result = parseRecordOrObject(p, nkObjectTy, definition)
|
||||
of pxParLe: result = parseEnum(p)
|
||||
of pxArray:
|
||||
@@ -1399,7 +1399,7 @@ proc fixVarSection(p: var TParser, counter: PNode) =
|
||||
|
||||
proc exSymbols(n: PNode) =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: nil
|
||||
of nkEmpty..nkNilLit: discard
|
||||
of nkProcDef..nkIteratorDef: exSymbol(n.sons[namePos])
|
||||
of nkWhenStmt, nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): exSymbols(n.sons[i])
|
||||
@@ -1410,7 +1410,7 @@ proc exSymbols(n: PNode) =
|
||||
exSymbol(n.sons[i].sons[0])
|
||||
if n.sons[i].sons[2].kind == nkObjectTy:
|
||||
fixRecordDef(n.sons[i].sons[2])
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc parseBegin(p: var TParser, result: PNode) =
|
||||
getTok(p)
|
||||
|
||||
@@ -19,12 +19,12 @@ proc verboseOpen(s: PSym): PPassContext =
|
||||
|
||||
proc verboseProcess(context: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if context != nil: InternalError("logpass: context is not nil")
|
||||
if context != nil: internalError("logpass: context is not nil")
|
||||
if gVerbosity == 3:
|
||||
# system.nim deactivates all hints, for verbosity:3 we want the processing
|
||||
# messages nonetheless, so we activate them again unconditionally:
|
||||
incl(msgs.gNotes, hintProcessing)
|
||||
Message(n.info, hintProcessing, $idgen.gBackendId)
|
||||
message(n.info, hintProcessing, $idgen.gBackendId)
|
||||
|
||||
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
|
||||
|
||||
@@ -34,14 +34,14 @@ proc cleanUp(c: PPassContext, n: PNode): PNode =
|
||||
if optDeadCodeElim in gGlobalOptions or n == nil: return
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): discard cleanup(c, n.sons[i])
|
||||
for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i])
|
||||
of nkProcDef, nkMethodDef:
|
||||
if n.sons[namePos].kind == nkSym:
|
||||
var s = n.sons[namePos].sym
|
||||
if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s):
|
||||
s.ast.sons[bodyPos] = ast.emptyNode # free the memory
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
const cleanupPass* = makePass(process = cleanUp, close = cleanUp)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import
|
||||
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||
nimsets, syntaxes, times, rodread, semthreads, idgen
|
||||
nimsets, syntaxes, times, rodread, idgen
|
||||
|
||||
type
|
||||
TPassContext* = object of TObject # the pass's context
|
||||
@@ -30,8 +30,8 @@ type
|
||||
TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
|
||||
process: TPassProcess, close: TPassClose]
|
||||
|
||||
TPassData* = tuple[input: PNode, closeOutput: Pnode]
|
||||
TPasses* = openarray[TPass]
|
||||
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
||||
TPasses* = openArray[TPass]
|
||||
|
||||
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
||||
# nodes. These are passed to the other close procedures.
|
||||
@@ -74,7 +74,8 @@ proc astNeeded*(s: PSym): bool =
|
||||
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
||||
(s.typ.callConv != ccInline) and
|
||||
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
||||
result = semthreads.needsGlobalAnalysis()
|
||||
result = false
|
||||
# XXX this doesn't really make sense with excessive CTFE
|
||||
else:
|
||||
result = true
|
||||
|
||||
@@ -169,7 +170,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||
openPasses(a, module)
|
||||
if stream == nil:
|
||||
let filename = fileIdx.toFullPath
|
||||
s = LLStreamOpen(filename, fmRead)
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
rawMessage(errCannotOpenFile, filename)
|
||||
return
|
||||
@@ -195,7 +196,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||
if s.kind != llsStdIn: break
|
||||
closePasses(a)
|
||||
# id synchronization point for more consistent code generation:
|
||||
IDsynchronizationPoint(1000)
|
||||
idSynchronizationPoint(1000)
|
||||
else:
|
||||
openPassesCached(a, module, rd)
|
||||
var n = loadInitSection(rd)
|
||||
|
||||
@@ -40,7 +40,7 @@ proc canonKind(n: PNode): TNodeKind =
|
||||
of nkCallKinds: result = nkCall
|
||||
of nkStrLit..nkTripleStrLit: result = nkStrLit
|
||||
of nkFastAsgn: result = nkAsgn
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc sameKinds(a, b: PNode): bool {.inline.} =
|
||||
result = a.kind == b.kind or a.canonKind == b.canonKind
|
||||
@@ -87,22 +87,22 @@ proc matchChoice(c: PPatternContext, p, n: PNode): bool =
|
||||
if matches(c, p.sons[i], n): return true
|
||||
|
||||
proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool =
|
||||
var pp = GetLazy(c, param)
|
||||
var pp = getLazy(c, param)
|
||||
if pp != nil:
|
||||
# check if we got the same pattern (already unified):
|
||||
result = sameTrees(pp, n) #matches(c, pp, n)
|
||||
elif n.kind == nkArgList or checkTypes(c, param, n):
|
||||
PutLazy(c, param, n)
|
||||
putLazy(c, param, n)
|
||||
result = true
|
||||
|
||||
proc gather(c: PPatternContext, param: PSym, n: PNode) =
|
||||
var pp = GetLazy(c, param)
|
||||
var pp = getLazy(c, param)
|
||||
if pp != nil and pp.kind == nkArgList:
|
||||
pp.add(n)
|
||||
else:
|
||||
pp = newNodeI(nkArgList, n.info, 1)
|
||||
pp.sons[0] = n
|
||||
PutLazy(c, param, pp)
|
||||
putLazy(c, param, pp)
|
||||
|
||||
proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
|
||||
# match ``op * param`` or ``op *| param``
|
||||
@@ -148,7 +148,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
of "*": result = matchNested(c, p, n, rpn=false)
|
||||
of "**": result = matchNested(c, p, n, rpn=true)
|
||||
of "~": result = not matches(c, p.sons[1], n)
|
||||
else: InternalError(p.info, "invalid pattern")
|
||||
else: internalError(p.info, "invalid pattern")
|
||||
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
|
||||
# add(a, b)
|
||||
elif p.kind == nkCurlyExpr:
|
||||
@@ -237,15 +237,6 @@ proc addToArgList(result, n: PNode) =
|
||||
else:
|
||||
for i in 0 .. <n.len: result.add(n.sons[i])
|
||||
|
||||
when false:
|
||||
proc procPatternMatches*(c: PContext, s: PSym, n: PNode): bool =
|
||||
## for AST-based overloading:
|
||||
var ctx: TPatternContext
|
||||
ctx.owner = s
|
||||
ctx.c = c
|
||||
ctx.formals = sonsLen(s.typ)-1
|
||||
result = matches(ctx, s.ast.sons[patternPos], n)
|
||||
|
||||
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
## returns a tree to semcheck if the rule triggered; nil otherwise
|
||||
var ctx: TPatternContext
|
||||
@@ -265,7 +256,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
args = newNodeI(nkArgList, n.info)
|
||||
for i in 1 .. < params.len:
|
||||
let param = params.sons[i].sym
|
||||
let x = GetLazy(ctx, param)
|
||||
let x = getLazy(ctx, param)
|
||||
# couldn't bind parameter:
|
||||
if isNil(x): return nil
|
||||
result.add(x)
|
||||
@@ -276,7 +267,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
var rs = result.sons[i]
|
||||
let param = params.sons[i].sym
|
||||
case whichAlias(param)
|
||||
of aqNone: nil
|
||||
of aqNone: discard
|
||||
of aqShouldAlias:
|
||||
# it suffices that it aliases for sure with *some* other param:
|
||||
var ok = false
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import
|
||||
llstream, lexer, parser, idents, strutils, ast, msgs
|
||||
|
||||
proc ParseAll*(p: var TParser): PNode =
|
||||
proc parseAll*(p: var TParser): PNode =
|
||||
result = nil
|
||||
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode =
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import
|
||||
llstream, lexer, parser, idents, strutils, ast, msgs
|
||||
|
||||
proc ParseAll*(p: var TParser): PNode =
|
||||
result = nil
|
||||
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode =
|
||||
result = nil
|
||||
|
||||
@@ -147,7 +147,7 @@ const
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
|
||||
(name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {})]
|
||||
|
||||
type
|
||||
@@ -185,13 +185,13 @@ var
|
||||
targetCPU*, hostCPU*: TSystemCPU
|
||||
targetOS*, hostOS*: TSystemOS
|
||||
|
||||
proc NameToOS*(name: string): TSystemOS
|
||||
proc NameToCPU*(name: string): TSystemCPU
|
||||
proc nameToOS*(name: string): TSystemOS
|
||||
proc nameToCPU*(name: string): TSystemCPU
|
||||
|
||||
var
|
||||
IntSize*: int
|
||||
intSize*: int
|
||||
floatSize*: int
|
||||
PtrSize*: int
|
||||
ptrSize*: int
|
||||
tnl*: string # target newline
|
||||
|
||||
proc setTarget*(o: TSystemOS, c: TSystemCPU) =
|
||||
@@ -200,18 +200,18 @@ proc setTarget*(o: TSystemOS, c: TSystemCPU) =
|
||||
#echo "new Target: OS: ", o, " CPU: ", c
|
||||
targetCPU = c
|
||||
targetOS = o
|
||||
intSize = cpu[c].intSize div 8
|
||||
floatSize = cpu[c].floatSize div 8
|
||||
ptrSize = cpu[c].bit div 8
|
||||
tnl = os[o].newLine
|
||||
intSize = CPU[c].intSize div 8
|
||||
floatSize = CPU[c].floatSize div 8
|
||||
ptrSize = CPU[c].bit div 8
|
||||
tnl = OS[o].newLine
|
||||
|
||||
proc NameToOS(name: string): TSystemOS =
|
||||
proc nameToOS(name: string): TSystemOS =
|
||||
for i in countup(succ(osNone), high(TSystemOS)):
|
||||
if cmpIgnoreStyle(name, OS[i].name) == 0:
|
||||
return i
|
||||
result = osNone
|
||||
|
||||
proc NameToCPU(name: string): TSystemCPU =
|
||||
proc nameToCPU(name: string): TSystemCPU =
|
||||
for i in countup(succ(cpuNone), high(TSystemCPU)):
|
||||
if cmpIgnoreStyle(name, CPU[i].name) == 0:
|
||||
return i
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -20,62 +20,65 @@ const
|
||||
|
||||
const
|
||||
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
||||
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||
wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist,
|
||||
wGenSym, wInject, wRaises, wTags}
|
||||
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wTags, wUses, wOperator, wDelegator, wGcSafe}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas
|
||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
|
||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
wDelegator}
|
||||
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
||||
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
||||
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
|
||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
||||
wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
|
||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
|
||||
wTags}
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||
wTags, wUses, wOperator, wGcSafe}
|
||||
exprPragmas* = {wLine}
|
||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||
wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
|
||||
wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
|
||||
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wEffects, wNoForward}
|
||||
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
|
||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||
wInjectStmt}
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
||||
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
|
||||
wRaises, wTags}
|
||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||
wRaises, wUses, wTags, wGcSafe}
|
||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
|
||||
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGenSym, wInject}
|
||||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||
wImportcpp, wImportobjc, wError}
|
||||
wImportCpp, wImportObjC, wError}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
|
||||
wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGenSym, wInject}
|
||||
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl}
|
||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||
wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject}
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
||||
wThread, wRaises, wTags}
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||
wThread, wRaises, wUses, wTags, wGcSafe}
|
||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||
|
||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||
# implementation
|
||||
|
||||
proc invalidPragma(n: PNode) =
|
||||
LocalError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
|
||||
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
result = '\0'
|
||||
if n != nil:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
if (it.kind == nkExprColonExpr) and (it.sons[0].kind == nkIdent):
|
||||
if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
|
||||
case whichKeyword(it.sons[0].ident)
|
||||
of wSubsChar:
|
||||
if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
|
||||
@@ -84,16 +87,33 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
else:
|
||||
invalidPragma(it)
|
||||
|
||||
proc setExternName(s: PSym, extname: string) =
|
||||
proc setExternName(s: PSym, extname: string) =
|
||||
s.loc.r = toRope(extname % s.name.s)
|
||||
if gCmd == cmdPretty and '$' notin extname:
|
||||
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
|
||||
s.loc.flags.incl(lfFullExternalName)
|
||||
|
||||
proc MakeExternImport(s: PSym, extname: string) =
|
||||
proc makeExternImport(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
incl(s.flags, sfImportc)
|
||||
excl(s.flags, sfForward)
|
||||
|
||||
proc MakeExternExport(s: PSym, extname: string) =
|
||||
proc validateExternCName(s: PSym, info: TLineInfo) =
|
||||
## Validates that the symbol name in s.loc.r is a valid C identifier.
|
||||
##
|
||||
## Valid identifiers are those alphanumeric including the underscore not
|
||||
## starting with a number. If the check fails, a generic error will be
|
||||
## displayed to the user.
|
||||
let target = ropeToStr(s.loc.r)
|
||||
if target.len < 1 or target[0] notin IdentStartChars or
|
||||
not target.allCharsInSet(IdentChars):
|
||||
localError(info, errGenerated, "invalid exported symbol")
|
||||
|
||||
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(s, extname)
|
||||
# XXX to fix make it work with nimrtl.
|
||||
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
|
||||
# validateExternCName(s, info)
|
||||
incl(s.flags, sfExportc)
|
||||
|
||||
proc processImportCompilerProc(s: PSym, extname: string) =
|
||||
@@ -120,7 +140,7 @@ proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
|
||||
|
||||
proc getStrLitNode(c: PContext, n: PNode): PNode =
|
||||
if n.kind != nkExprColonExpr:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
localError(n.info, errStringLiteralExpected)
|
||||
# error correction:
|
||||
result = newEmptyStrNode(n)
|
||||
else:
|
||||
@@ -128,7 +148,7 @@ proc getStrLitNode(c: PContext, n: PNode): PNode =
|
||||
case n.sons[1].kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
|
||||
else:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
localError(n.info, errStringLiteralExpected)
|
||||
# error correction:
|
||||
result = newEmptyStrNode(n)
|
||||
|
||||
@@ -137,22 +157,25 @@ proc expectStrLit(c: PContext, n: PNode): string =
|
||||
|
||||
proc expectIntLit(c: PContext, n: PNode): int =
|
||||
if n.kind != nkExprColonExpr:
|
||||
LocalError(n.info, errIntLiteralExpected)
|
||||
localError(n.info, errIntLiteralExpected)
|
||||
else:
|
||||
n.sons[1] = c.semConstExpr(c, n.sons[1])
|
||||
case n.sons[1].kind
|
||||
of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
|
||||
else: LocalError(n.info, errIntLiteralExpected)
|
||||
else: localError(n.info, errIntLiteralExpected)
|
||||
|
||||
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
|
||||
if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
|
||||
else: result = defaultStr
|
||||
|
||||
|
||||
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
|
||||
sym.constraint = getStrLitNode(c, n)
|
||||
|
||||
proc processMagic(c: PContext, n: PNode, s: PSym) =
|
||||
#if sfSystemModule notin c.module.flags:
|
||||
# liMessage(n.info, errMagicOnlyInSystem)
|
||||
if n.kind != nkExprColonExpr:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
localError(n.info, errStringLiteralExpected)
|
||||
return
|
||||
var v: string
|
||||
if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
|
||||
@@ -161,57 +184,57 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
|
||||
if substr($m, 1) == v:
|
||||
s.magic = m
|
||||
break
|
||||
if s.magic == mNone: Message(n.info, warnUnknownMagic, v)
|
||||
if s.magic == mNone: message(n.info, warnUnknownMagic, v)
|
||||
|
||||
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
|
||||
# this assumes that the order of special words and calling conventions is
|
||||
# the same
|
||||
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
|
||||
|
||||
proc IsTurnedOn(c: PContext, n: PNode): bool =
|
||||
proc isTurnedOn(c: PContext, n: PNode): bool =
|
||||
if n.kind == nkExprColonExpr:
|
||||
let x = c.semConstBoolExpr(c, n.sons[1])
|
||||
n.sons[1] = x
|
||||
if x.kind == nkIntLit: return x.intVal != 0
|
||||
LocalError(n.info, errOnOrOffExpected)
|
||||
localError(n.info, errOnOrOffExpected)
|
||||
|
||||
proc onOff(c: PContext, n: PNode, op: TOptions) =
|
||||
if IsTurnedOn(c, n): gOptions = gOptions + op
|
||||
if isTurnedOn(c, n): gOptions = gOptions + op
|
||||
else: gOptions = gOptions - op
|
||||
|
||||
proc pragmaDeadCodeElim(c: PContext, n: PNode) =
|
||||
if IsTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
|
||||
if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
|
||||
else: excl(c.module.flags, sfDeadCodeElim)
|
||||
|
||||
proc pragmaNoForward(c: PContext, n: PNode) =
|
||||
if IsTurnedOn(c, n): incl(c.module.flags, sfNoForward)
|
||||
if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
|
||||
else: excl(c.module.flags, sfNoForward)
|
||||
|
||||
proc processCallConv(c: PContext, n: PNode) =
|
||||
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
|
||||
var sw = whichKeyword(n.sons[1].ident)
|
||||
case sw
|
||||
of firstCallConv..lastCallConv:
|
||||
of FirstCallConv..LastCallConv:
|
||||
POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw)
|
||||
else: LocalError(n.info, errCallConvExpected)
|
||||
else: localError(n.info, errCallConvExpected)
|
||||
else:
|
||||
LocalError(n.info, errCallConvExpected)
|
||||
localError(n.info, errCallConvExpected)
|
||||
|
||||
proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
|
||||
var it = PLib(c.libs.head)
|
||||
while it != nil:
|
||||
if it.kind == kind:
|
||||
if trees.ExprStructuralEquivalent(it.path, path): return it
|
||||
if trees.exprStructuralEquivalent(it.path, path): return it
|
||||
it = PLib(it.next)
|
||||
result = newLib(kind)
|
||||
result.path = path
|
||||
Append(c.libs, result)
|
||||
append(c.libs, result)
|
||||
if path.kind in {nkStrLit..nkTripleStrLit}:
|
||||
result.isOverriden = options.isDynLibOverride(path.strVal)
|
||||
result.isOverriden = options.isDynlibOverride(path.strVal)
|
||||
|
||||
proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
if n.kind != nkExprColonExpr:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
localError(n.info, errStringLiteralExpected)
|
||||
# error correction:
|
||||
result = newEmptyStrNode(n)
|
||||
else:
|
||||
@@ -221,7 +244,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
if result.kind == nkSym and result.sym.kind == skConst:
|
||||
result = result.sym.ast # look it up
|
||||
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
localError(n.info, errStringLiteralExpected)
|
||||
result = newEmptyStrNode(n)
|
||||
|
||||
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
@@ -239,7 +262,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
# since we'll be loading the dynlib symbols dynamically, we must use
|
||||
# a calling convention that doesn't introduce custom name mangling
|
||||
# cdecl is the default - the user can override this explicitly
|
||||
if sym.kind in RoutineKinds and sym.typ != nil and
|
||||
if sym.kind in routineKinds and sym.typ != nil and
|
||||
sym.typ.callConv == ccDefault:
|
||||
sym.typ.callConv = ccCDecl
|
||||
|
||||
@@ -253,11 +276,11 @@ proc processNote(c: PContext, n: PNode) =
|
||||
of wHint:
|
||||
var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
|
||||
if x >= 0: nk = TNoteKind(x + ord(hintMin))
|
||||
else: invalidPragma(n)
|
||||
else: invalidPragma(n); return
|
||||
of wWarning:
|
||||
var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
|
||||
if x >= 0: nk = TNoteKind(x + ord(warnMin))
|
||||
else: InvalidPragma(n)
|
||||
else: invalidPragma(n); return
|
||||
else:
|
||||
invalidPragma(n)
|
||||
return
|
||||
@@ -276,27 +299,27 @@ proc processOption(c: PContext, n: PNode): bool =
|
||||
else:
|
||||
var sw = whichKeyword(n.sons[0].ident)
|
||||
case sw
|
||||
of wChecks: OnOff(c, n, checksOptions)
|
||||
of wObjChecks: OnOff(c, n, {optObjCheck})
|
||||
of wFieldchecks: OnOff(c, n, {optFieldCheck})
|
||||
of wRangechecks: OnOff(c, n, {optRangeCheck})
|
||||
of wBoundchecks: OnOff(c, n, {optBoundsCheck})
|
||||
of wOverflowchecks: OnOff(c, n, {optOverflowCheck})
|
||||
of wNilchecks: OnOff(c, n, {optNilCheck})
|
||||
of wFloatChecks: OnOff(c, n, {optNanCheck, optInfCheck})
|
||||
of wNaNchecks: OnOff(c, n, {optNanCheck})
|
||||
of wInfChecks: OnOff(c, n, {optInfCheck})
|
||||
of wAssertions: OnOff(c, n, {optAssert})
|
||||
of wWarnings: OnOff(c, n, {optWarns})
|
||||
of wHints: OnOff(c, n, {optHints})
|
||||
of wCallConv: processCallConv(c, n)
|
||||
of wLinedir: OnOff(c, n, {optLineDir})
|
||||
of wStacktrace: OnOff(c, n, {optStackTrace})
|
||||
of wLinetrace: OnOff(c, n, {optLineTrace})
|
||||
of wDebugger: OnOff(c, n, {optEndb})
|
||||
of wProfiler: OnOff(c, n, {optProfiler})
|
||||
of wByRef: OnOff(c, n, {optByRef})
|
||||
of wDynLib: processDynLib(c, n, nil)
|
||||
of wChecks: onOff(c, n, ChecksOptions)
|
||||
of wObjChecks: onOff(c, n, {optObjCheck})
|
||||
of wFieldChecks: onOff(c, n, {optFieldCheck})
|
||||
of wRangechecks: onOff(c, n, {optRangeCheck})
|
||||
of wBoundchecks: onOff(c, n, {optBoundsCheck})
|
||||
of wOverflowchecks: onOff(c, n, {optOverflowCheck})
|
||||
of wNilchecks: onOff(c, n, {optNilCheck})
|
||||
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
|
||||
of wNanChecks: onOff(c, n, {optNaNCheck})
|
||||
of wInfChecks: onOff(c, n, {optInfCheck})
|
||||
of wAssertions: onOff(c, n, {optAssert})
|
||||
of wWarnings: onOff(c, n, {optWarns})
|
||||
of wHints: onOff(c, n, {optHints})
|
||||
of wCallconv: processCallConv(c, n)
|
||||
of wLinedir: onOff(c, n, {optLineDir})
|
||||
of wStacktrace: onOff(c, n, {optStackTrace})
|
||||
of wLinetrace: onOff(c, n, {optLineTrace})
|
||||
of wDebugger: onOff(c, n, {optEndb})
|
||||
of wProfiler: onOff(c, n, {optProfiler})
|
||||
of wByRef: onOff(c, n, {optByRef})
|
||||
of wDynlib: processDynLib(c, n, nil)
|
||||
of wOptimization:
|
||||
if n.sons[1].kind != nkIdent:
|
||||
invalidPragma(n)
|
||||
@@ -311,14 +334,14 @@ proc processOption(c: PContext, n: PNode): bool =
|
||||
of "none":
|
||||
excl(gOptions, optOptimizeSpeed)
|
||||
excl(gOptions, optOptimizeSize)
|
||||
else: LocalError(n.info, errNoneSpeedOrSizeExpected)
|
||||
of wImplicitStatic: OnOff(c, n, {optImplicitStatic})
|
||||
of wPatterns: OnOff(c, n, {optPatterns})
|
||||
else: localError(n.info, errNoneSpeedOrSizeExpected)
|
||||
of wImplicitStatic: onOff(c, n, {optImplicitStatic})
|
||||
of wPatterns: onOff(c, n, {optPatterns})
|
||||
else: result = true
|
||||
|
||||
proc processPush(c: PContext, n: PNode, start: int) =
|
||||
if n.sons[start-1].kind == nkExprColonExpr:
|
||||
LocalError(n.info, errGenerated, "':' after 'push' not supported")
|
||||
localError(n.info, errGenerated, "':' after 'push' not supported")
|
||||
var x = newOptionEntry()
|
||||
var y = POptionEntry(c.optionStack.tail)
|
||||
x.options = gOptions
|
||||
@@ -336,7 +359,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||
|
||||
proc processPop(c: PContext, n: PNode) =
|
||||
if c.optionStack.counter <= 1:
|
||||
LocalError(n.info, errAtPopWithoutPush)
|
||||
localError(n.info, errAtPopWithoutPush)
|
||||
else:
|
||||
gOptions = POptionEntry(c.optionStack.tail).options
|
||||
gNotes = POptionEntry(c.optionStack.tail).notes
|
||||
@@ -344,15 +367,15 @@ proc processPop(c: PContext, n: PNode) =
|
||||
|
||||
proc processDefine(c: PContext, n: PNode) =
|
||||
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
|
||||
DefineSymbol(n.sons[1].ident.s)
|
||||
Message(n.info, warnDeprecated, "define")
|
||||
defineSymbol(n.sons[1].ident.s)
|
||||
message(n.info, warnDeprecated, "define")
|
||||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
proc processUndef(c: PContext, n: PNode) =
|
||||
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
|
||||
UndefSymbol(n.sons[1].ident.s)
|
||||
Message(n.info, warnDeprecated, "undef")
|
||||
undefSymbol(n.sons[1].ident.s)
|
||||
message(n.info, warnDeprecated, "undef")
|
||||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
@@ -364,13 +387,13 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
var s = expectStrLit(c, n)
|
||||
var found = findFile(s)
|
||||
if found == "": found = s
|
||||
var trunc = ChangeFileExt(found, "")
|
||||
var trunc = changeFileExt(found, "")
|
||||
extccomp.addExternalFileToCompile(found)
|
||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||
|
||||
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
||||
var f = expectStrLit(c, n)
|
||||
if splitFile(f).ext == "": f = addFileExt(f, cc[ccompiler].objExt)
|
||||
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
|
||||
var found = findFile(f)
|
||||
if found == "": found = f # use the default
|
||||
case feature
|
||||
@@ -379,16 +402,16 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
||||
extccomp.addFileToLink(libpath / completeCFilePath(found, false))
|
||||
else: internalError(n.info, "processCommonLink")
|
||||
|
||||
proc PragmaBreakpoint(c: PContext, n: PNode) =
|
||||
proc pragmaBreakpoint(c: PContext, n: PNode) =
|
||||
discard getOptionalStr(c, n, "")
|
||||
|
||||
proc PragmaCheckpoint(c: PContext, n: PNode) =
|
||||
proc pragmaCheckpoint(c: PContext, n: PNode) =
|
||||
# checkpoints can be used to debug the compiler; they are not documented
|
||||
var info = n.info
|
||||
inc(info.line) # next line is affected!
|
||||
msgs.addCheckpoint(info)
|
||||
|
||||
proc PragmaWatchpoint(c: PContext, n: PNode) =
|
||||
proc pragmaWatchpoint(c: PContext, n: PNode) =
|
||||
if n.kind == nkExprColonExpr:
|
||||
n.sons[1] = c.semExpr(c, n.sons[1])
|
||||
else:
|
||||
@@ -396,11 +419,11 @@ proc PragmaWatchpoint(c: PContext, n: PNode) =
|
||||
|
||||
proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
|
||||
case n.sons[1].kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
result = copyNode(n)
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
|
||||
var str = n.sons[1].strVal
|
||||
if str == "":
|
||||
LocalError(n.info, errEmptyAsm)
|
||||
localError(n.info, errEmptyAsm)
|
||||
return
|
||||
# now parse the string literal and substitute symbols:
|
||||
var a = 0
|
||||
@@ -423,14 +446,14 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
|
||||
a = c + 1
|
||||
else: illFormedAst(n)
|
||||
|
||||
proc PragmaEmit(c: PContext, n: PNode) =
|
||||
proc pragmaEmit(c: PContext, n: PNode) =
|
||||
discard getStrLitNode(c, n)
|
||||
n.sons[1] = semAsmOrEmit(c, n, '`')
|
||||
|
||||
proc noVal(n: PNode) =
|
||||
if n.kind == nkExprColonExpr: invalidPragma(n)
|
||||
|
||||
proc PragmaUnroll(c: PContext, n: PNode) =
|
||||
proc pragmaUnroll(c: PContext, n: PNode) =
|
||||
if c.p.nestedLoopCounter <= 0:
|
||||
invalidPragma(n)
|
||||
elif n.kind == nkExprColonExpr:
|
||||
@@ -440,10 +463,7 @@ proc PragmaUnroll(c: PContext, n: PNode) =
|
||||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
proc PragmaLinearScanEnd(c: PContext, n: PNode) =
|
||||
noVal(n)
|
||||
|
||||
proc PragmaLine(c: PContext, n: PNode) =
|
||||
proc pragmaLine(c: PContext, n: PNode) =
|
||||
if n.kind == nkExprColonExpr:
|
||||
n.sons[1] = c.semConstExpr(c, n.sons[1])
|
||||
let a = n.sons[1]
|
||||
@@ -453,14 +473,14 @@ proc PragmaLine(c: PContext, n: PNode) =
|
||||
if x.kind == nkExprColonExpr: x = x.sons[1]
|
||||
if y.kind == nkExprColonExpr: y = y.sons[1]
|
||||
if x.kind != nkStrLit:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
localError(n.info, errStringLiteralExpected)
|
||||
elif y.kind != nkIntLit:
|
||||
LocalError(n.info, errIntLiteralExpected)
|
||||
localError(n.info, errIntLiteralExpected)
|
||||
else:
|
||||
n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
|
||||
n.info.line = int16(y.intVal)
|
||||
else:
|
||||
LocalError(n.info, errXExpected, "tuple")
|
||||
localError(n.info, errXExpected, "tuple")
|
||||
else:
|
||||
# sensible default:
|
||||
n.info = getInfoContext(-1)
|
||||
@@ -471,11 +491,11 @@ proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
elif it.sons[0].kind != nkIdent: invalidPragma(n)
|
||||
elif it.sons[1].kind != nkIdent: invalidPragma(n)
|
||||
|
||||
var userPragma = NewSym(skTemplate, it.sons[1].ident, nil, it.info)
|
||||
var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
|
||||
var body = newNodeI(nkPragma, n.info)
|
||||
for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
|
||||
userPragma.ast = body
|
||||
StrTableAdd(c.userPragmas, userPragma)
|
||||
strTableAdd(c.userPragmas, userPragma)
|
||||
|
||||
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||
proc processExc(c: PContext, x: PNode) =
|
||||
@@ -493,28 +513,56 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
proc pragmaUses(c: PContext, n: PNode) =
|
||||
proc processExc(c: PContext, x: PNode): PNode =
|
||||
if x.kind in {nkAccQuoted, nkIdent, nkSym,
|
||||
nkOpenSymChoice, nkClosedSymChoice}:
|
||||
if considerAcc(x).s == "*":
|
||||
return newSymNode(ast.anyGlobal)
|
||||
result = c.semExpr(c, x)
|
||||
if result.kind != nkSym or sfGlobal notin result.sym.flags:
|
||||
localError(x.info, "'$1' is not a global variable" % result.renderTree)
|
||||
result = newSymNode(ast.anyGlobal)
|
||||
|
||||
if n.kind == nkExprColonExpr:
|
||||
let it = n.sons[1]
|
||||
if it.kind notin {nkCurly, nkBracket}:
|
||||
n.sons[1] = processExc(c, it)
|
||||
else:
|
||||
for i in 0 .. <it.len:
|
||||
it.sons[i] = processExc(c, it.sons[i])
|
||||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
proc typeBorrow(sym: PSym, n: PNode) =
|
||||
if n.kind == nkExprColonExpr:
|
||||
let it = n.sons[1]
|
||||
if it.kind != nkAccQuoted:
|
||||
localError(n.info, "a type can only borrow `.` for now")
|
||||
incl(sym.typ.flags, tfBorrowDot)
|
||||
|
||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
validPragmas: TSpecialWords): bool =
|
||||
var it = n.sons[i]
|
||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||
if key.kind == nkIdent:
|
||||
var userPragma = StrTableGet(c.userPragmas, key.ident)
|
||||
var userPragma = strTableGet(c.userPragmas, key.ident)
|
||||
if userPragma != nil:
|
||||
inc c.InstCounter
|
||||
if c.InstCounter > 100:
|
||||
GlobalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||
inc c.instCounter
|
||||
if c.instCounter > 100:
|
||||
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||
pragma(c, sym, userPragma.ast, validPragmas)
|
||||
dec c.InstCounter
|
||||
dec c.instCounter
|
||||
else:
|
||||
var k = whichKeyword(key.ident)
|
||||
if k in validPragmas:
|
||||
case k
|
||||
of wExportc:
|
||||
makeExternExport(sym, getOptionalStr(c, it, sym.name.s))
|
||||
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
incl(sym.flags, sfUsed) # avoid wrong hints
|
||||
of wImportc: makeExternImport(sym, getOptionalStr(c, it, sym.name.s))
|
||||
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
|
||||
of wImportCompilerProc:
|
||||
processImportCompilerProc(sym, getOptionalStr(c, it, sym.name.s))
|
||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
|
||||
of wExtern: setExternName(sym, expectStrLit(c, it))
|
||||
of wImmediate:
|
||||
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
|
||||
@@ -523,29 +571,31 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
||||
else: invalidPragma(it)
|
||||
of wImportCpp:
|
||||
processImportCpp(sym, getOptionalStr(c, it, sym.name.s))
|
||||
processImportCpp(sym, getOptionalStr(c, it, "$1"))
|
||||
of wImportObjC:
|
||||
processImportObjC(sym, getOptionalStr(c, it, sym.name.s))
|
||||
processImportObjC(sym, getOptionalStr(c, it, "$1"))
|
||||
of wAlign:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var align = expectIntLit(c, it)
|
||||
if not IsPowerOfTwo(align) and align != 0:
|
||||
LocalError(it.info, errPowerOfTwoExpected)
|
||||
if not isPowerOfTwo(align) and align != 0:
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.align = align
|
||||
of wSize:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var size = expectIntLit(c, it)
|
||||
if not IsPowerOfTwo(size) or size <= 0 or size > 8:
|
||||
LocalError(it.info, errPowerOfTwoExpected)
|
||||
if not isPowerOfTwo(size) or size <= 0 or size > 8:
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.size = size
|
||||
of wNodecl:
|
||||
noVal(it)
|
||||
incl(sym.loc.Flags, lfNoDecl)
|
||||
of wPure, wNoStackFrame:
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wPure, wAsmNoStackFrame:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfPure)
|
||||
if sym != nil:
|
||||
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
|
||||
else: incl(sym.flags, sfPure)
|
||||
of wVolatile:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfVolatile)
|
||||
@@ -561,19 +611,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wCompileTime:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfCompileTime)
|
||||
incl(sym.loc.Flags, lfNoDecl)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wGlobal:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfGlobal)
|
||||
incl(sym.flags, sfPure)
|
||||
of wMerge:
|
||||
noval(it)
|
||||
noVal(it)
|
||||
incl(sym.flags, sfMerge)
|
||||
of wHeader:
|
||||
var lib = getLib(c, libHeader, getStrLitNode(c, it))
|
||||
addToLib(lib, sym)
|
||||
incl(sym.flags, sfImportc)
|
||||
incl(sym.loc.flags, lfHeader)
|
||||
incl(sym.loc.Flags, lfNoDecl)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||
of wDestructor:
|
||||
@@ -585,23 +636,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||
of wSideEffect:
|
||||
of wSideeffect:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfSideEffect)
|
||||
of wNoReturn:
|
||||
of wNoreturn:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoReturn)
|
||||
of wDynLib:
|
||||
of wDynlib:
|
||||
processDynLib(c, it, sym)
|
||||
of wCompilerProc:
|
||||
of wCompilerproc:
|
||||
noVal(it) # compilerproc may not get a string!
|
||||
makeExternExport(sym, sym.name.s)
|
||||
makeExternExport(sym, "$1", it.info)
|
||||
incl(sym.flags, sfCompilerProc)
|
||||
incl(sym.flags, sfUsed) # suppress all those stupid warnings
|
||||
registerCompilerProc(sym)
|
||||
of wProcvar:
|
||||
of wProcVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfProcVar)
|
||||
incl(sym.flags, sfProcvar)
|
||||
of wDeprecated:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfDeprecated)
|
||||
@@ -610,9 +661,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfVarargs)
|
||||
of wBorrow:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfBorrow)
|
||||
of wBorrow:
|
||||
if sym.kind == skType:
|
||||
typeBorrow(sym, it)
|
||||
else:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfBorrow)
|
||||
of wFinal:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
@@ -632,10 +686,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wThread:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfThread)
|
||||
incl(sym.flags, sfProcVar)
|
||||
incl(sym.flags, sfProcvar)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
||||
of wHint: Message(it.info, hintUser, expectStrLit(c, it))
|
||||
of wWarning: Message(it.info, warnUser, expectStrLit(c, it))
|
||||
of wGcSafe:
|
||||
if optThreadAnalysis in gGlobalOptions:
|
||||
noVal(it)
|
||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||
else: invalidPragma(it)
|
||||
of wPacked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfPacked)
|
||||
of wHint: message(it.info, hintUser, expectStrLit(c, it))
|
||||
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
|
||||
of wError:
|
||||
if sym != nil and sym.isRoutine:
|
||||
# This is subtle but correct: the error *statement* is only
|
||||
@@ -645,17 +709,17 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
noVal(it)
|
||||
incl(sym.flags, sfError)
|
||||
else:
|
||||
LocalError(it.info, errUser, expectStrLit(c, it))
|
||||
of wFatal: Fatal(it.info, errUser, expectStrLit(c, it))
|
||||
localError(it.info, errUser, expectStrLit(c, it))
|
||||
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
|
||||
of wDefine: processDefine(c, it)
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile: processCompile(c, it)
|
||||
of wLink: processCommonLink(c, it, linkNormal)
|
||||
of wLinkSys: processCommonLink(c, it, linkSys)
|
||||
of wPassL: extccomp.addLinkOption(expectStrLit(c, it))
|
||||
of wPassC: extccomp.addCompileOption(expectStrLit(c, it))
|
||||
of wBreakpoint: PragmaBreakpoint(c, it)
|
||||
of wWatchpoint: PragmaWatchpoint(c, it)
|
||||
of wLinksys: processCommonLink(c, it, linkSys)
|
||||
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
|
||||
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
|
||||
of wBreakpoint: pragmaBreakpoint(c, it)
|
||||
of wWatchPoint: pragmaWatchpoint(c, it)
|
||||
of wPush:
|
||||
processPush(c, n, i + 1)
|
||||
result = true
|
||||
@@ -669,25 +733,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wNoInit:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfNoInit)
|
||||
of wHoist:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfHoist)
|
||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization,
|
||||
wCallConv,
|
||||
wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks,
|
||||
wCallconv,
|
||||
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
|
||||
wPatterns:
|
||||
if processOption(c, it):
|
||||
# calling conventions (boring...):
|
||||
LocalError(it.info, errOptionExpected)
|
||||
of firstCallConv..lastCallConv:
|
||||
localError(it.info, errOptionExpected)
|
||||
of FirstCallConv..LastCallConv:
|
||||
assert(sym != nil)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: sym.typ.callConv = wordToCallConv(k)
|
||||
of wEmit: PragmaEmit(c, it)
|
||||
of wUnroll: PragmaUnroll(c, it)
|
||||
of wLinearScanEnd: PragmaLinearScanEnd(c, it)
|
||||
of wEmit: pragmaEmit(c, it)
|
||||
of wUnroll: pragmaUnroll(c, it)
|
||||
of wLinearScanEnd, wComputedGoto: noVal(it)
|
||||
of wEffects:
|
||||
# is later processed in effect analysis:
|
||||
noVal(it)
|
||||
@@ -695,50 +757,82 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfIncompleteStruct)
|
||||
of wUnchecked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfUncheckedArray)
|
||||
of wUnion:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfUnion)
|
||||
of wRequiresInit:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfNeedsInit)
|
||||
of wByRef:
|
||||
noVal(it)
|
||||
if sym == nil or sym.typ == nil:
|
||||
if processOption(c, it): LocalError(it.info, errOptionExpected)
|
||||
if processOption(c, it): localError(it.info, errOptionExpected)
|
||||
else:
|
||||
incl(sym.typ.flags, tfByRef)
|
||||
of wByCopy:
|
||||
noVal(it)
|
||||
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfByCopy)
|
||||
of wInject, wGenSym:
|
||||
of wInject, wGensym:
|
||||
# We check for errors, but do nothing with these pragmas otherwise
|
||||
# as they are handled directly in 'evalTemplate'.
|
||||
noVal(it)
|
||||
if sym == nil: invalidPragma(it)
|
||||
of wLine: PragmaLine(c, it)
|
||||
of wLine: pragmaLine(c, it)
|
||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||
of wUses: pragmaUses(c, it)
|
||||
of wOperator:
|
||||
if sym == nil: invalidPragma(it)
|
||||
else: sym.position = expectIntLit(c, it)
|
||||
of wInjectStmt:
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(it.info, errExprExpected)
|
||||
else:
|
||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||
else: invalidPragma(it)
|
||||
else: invalidPragma(it)
|
||||
else: processNote(c, it)
|
||||
|
||||
proc implictPragmas*(c: PContext, sym: PSym, n: PNode,
|
||||
validPragmas: TSpecialWords) =
|
||||
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
|
||||
validPragmas: TSpecialWords) =
|
||||
if sym != nil and sym.kind != skModule:
|
||||
var it = POptionEntry(c.optionstack.head)
|
||||
var it = POptionEntry(c.optionStack.head)
|
||||
while it != nil:
|
||||
let o = it.otherPragmas
|
||||
if not o.isNil:
|
||||
for i in countup(0, sonsLen(o) - 1):
|
||||
if singlePragma(c, sym, o, i, validPragmas):
|
||||
InternalError(n.info, "implicitPragmas")
|
||||
internalError(n.info, "implicitPragmas")
|
||||
it = it.next.POptionEntry
|
||||
|
||||
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
|
||||
LocalError(n.info, errDynlibRequiresExportc)
|
||||
var lib = POptionEntry(c.optionstack.tail).dynlib
|
||||
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
|
||||
localError(n.info, errDynlibRequiresExportc)
|
||||
var lib = POptionEntry(c.optionStack.tail).dynlib
|
||||
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
|
||||
sfImportc in sym.flags and lib != nil:
|
||||
incl(sym.loc.flags, lfDynamicLib)
|
||||
addToLib(lib, sym)
|
||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||
|
||||
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
|
||||
if n == nil or n.sons == nil:
|
||||
return false
|
||||
|
||||
for p in n.sons:
|
||||
var key = if p.kind == nkExprColonExpr: p[0] else: p
|
||||
if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
if n == nil: return
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if singlePragma(c, sym, n, i, validPragmas): break
|
||||
implictPragmas(c, sym, n, validPragmas)
|
||||
implicitPragmas(c, sym, n, validPragmas)
|
||||
|
||||
325
compiler/pretty.nim
Normal file
325
compiler/pretty.nim
Normal file
@@ -0,0 +1,325 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements the code "prettifier". This is part of the toolchain
|
||||
## to convert Nimrod code into a consistent style.
|
||||
|
||||
import
|
||||
strutils, os, options, ast, astalgo, msgs, ropes, idents, passes,
|
||||
intsets, strtabs, semdata
|
||||
|
||||
const
|
||||
removeTP = false # when true, "nimrod pretty" converts TTyp to Typ.
|
||||
|
||||
type
|
||||
TGen = object of TPassContext
|
||||
module*: PSym
|
||||
PGen = ref TGen
|
||||
|
||||
TSourceFile = object
|
||||
lines: seq[string]
|
||||
dirty: bool
|
||||
fullpath: string
|
||||
|
||||
var
|
||||
gSourceFiles: seq[TSourceFile] = @[]
|
||||
gCheckExtern: bool
|
||||
rules: PStringTable
|
||||
|
||||
proc loadFile(info: TLineInfo) =
|
||||
let i = info.fileIndex
|
||||
if i >= gSourceFiles.len:
|
||||
gSourceFiles.setLen(i+1)
|
||||
if gSourceFiles[i].lines.isNil:
|
||||
gSourceFiles[i].lines = @[]
|
||||
let path = info.toFullPath
|
||||
gSourceFiles[i].fullpath = path
|
||||
# we want to die here for EIO:
|
||||
for line in lines(path):
|
||||
gSourceFiles[i].lines.add(line)
|
||||
|
||||
proc overwriteFiles*() =
|
||||
let overWrite = options.getConfigVar("pretty.overwrite").normalize == "on"
|
||||
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
|
||||
for i in 0 .. high(gSourceFiles):
|
||||
if not gSourceFiles[i].dirty: continue
|
||||
let newFile = if overWrite: gSourceFiles[i].fullpath
|
||||
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
|
||||
try:
|
||||
var f = open(newFile, fmWrite)
|
||||
for line in gSourceFiles[i].lines:
|
||||
if doStrip:
|
||||
f.write line.strip(leading = false, trailing = true)
|
||||
else:
|
||||
f.write line
|
||||
f.write("\L")
|
||||
f.close
|
||||
except EIO:
|
||||
rawMessage(errCannotOpenFile, newFile)
|
||||
|
||||
proc `=~`(s: string, a: openArray[string]): bool =
|
||||
for x in a:
|
||||
if s.startsWith(x): return true
|
||||
|
||||
proc beautifyName(s: string, k: TSymKind): string =
|
||||
# minimal set of rules here for transition:
|
||||
# GC_ is allowed
|
||||
|
||||
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
|
||||
if allUpper and k in {skConst, skEnumField, skType}: return s
|
||||
result = newStringOfCap(s.len)
|
||||
var i = 0
|
||||
case k
|
||||
of skType, skGenericParam:
|
||||
# Types should start with a capital unless builtins like 'int' etc.:
|
||||
when removeTP:
|
||||
if s[0] == 'T' and s[1] in {'A'..'Z'}:
|
||||
i = 1
|
||||
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
|
||||
"char", "byte", "bool", "openArray", "seq", "array", "void",
|
||||
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
|
||||
"cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
|
||||
"range", "openarray", "varargs", "set", "cfloat"
|
||||
]:
|
||||
result.add s[i]
|
||||
else:
|
||||
result.add toUpper(s[i])
|
||||
of skConst, skEnumField:
|
||||
# for 'const' we keep how it's spelt; either upper case or lower case:
|
||||
result.add s[0]
|
||||
else:
|
||||
# as a special rule, don't transform 'L' to 'l'
|
||||
if s.len == 1 and s[0] == 'L': result.add 'L'
|
||||
elif '_' in s: result.add(s[i])
|
||||
else: result.add toLower(s[0])
|
||||
inc i
|
||||
while i < s.len:
|
||||
if s[i] == '_':
|
||||
if i > 0 and s[i-1] in {'A'..'Z'}:
|
||||
# don't skip '_' as it's essential for e.g. 'GC_disable'
|
||||
result.add('_')
|
||||
inc i
|
||||
result.add s[i]
|
||||
else:
|
||||
inc i
|
||||
result.add toUpper(s[i])
|
||||
elif allUpper:
|
||||
result.add toLower(s[i])
|
||||
else:
|
||||
result.add s[i]
|
||||
inc i
|
||||
|
||||
proc checkStyle*(info: TLineInfo, s: string, k: TSymKind) =
|
||||
let beau = beautifyName(s, k)
|
||||
if s != beau:
|
||||
message(info, errGenerated, "name should be: " & beau)
|
||||
|
||||
const
|
||||
Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||
|
||||
proc identLen(line: string, start: int): int =
|
||||
while start+result < line.len and line[start+result] in Letters:
|
||||
inc result
|
||||
|
||||
proc differ(line: string, a, b: int, x: string): bool =
|
||||
let y = line[a..b]
|
||||
result = cmpIgnoreStyle(y, x) == 0 and y != x
|
||||
when false:
|
||||
var j = 0
|
||||
for i in a..b:
|
||||
if line[i] != x[j]: return true
|
||||
inc j
|
||||
return false
|
||||
|
||||
proc checkDef*(n: PNode; s: PSym) =
|
||||
# operators stay as they are:
|
||||
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
|
||||
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
|
||||
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
|
||||
checkStyle(n.info, s.name.s, s.kind)
|
||||
|
||||
proc checkDef(c: PGen; n: PNode) =
|
||||
if n.kind != nkSym: return
|
||||
checkDef(n, n.sym)
|
||||
|
||||
proc checkUse*(n: PNode, s: PSym) =
|
||||
if n.info.fileIndex < 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: return
|
||||
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
let newName = s.name.s
|
||||
|
||||
loadFile(n.info)
|
||||
|
||||
let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
|
||||
var first = min(n.info.col.int, line.len)
|
||||
if first < 0: return
|
||||
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||
while first > 0 and line[first-1] in Letters: dec first
|
||||
if first < 0: return
|
||||
if line[first] == '`': inc first
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
if differ(line, first, last, newName):
|
||||
# last-first+1 != newName.len or
|
||||
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
||||
when removeTP:
|
||||
# the WinAPI module is full of 'TX = X' which after the substitution
|
||||
# becomes 'X = X'. We remove those lines:
|
||||
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
|
||||
x = ""
|
||||
|
||||
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
|
||||
gSourceFiles[n.info.fileIndex].dirty = true
|
||||
|
||||
when false:
|
||||
var cannotRename = initIntSet()
|
||||
|
||||
proc beautifyName(s: string, k: TSymKind): string =
|
||||
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
|
||||
result = newStringOfCap(s.len)
|
||||
var i = 0
|
||||
case k
|
||||
of skType, skGenericParam:
|
||||
# skip leading 'T'
|
||||
when removeTP:
|
||||
if s[0] == 'T' and s[1] in {'A'..'Z'}:
|
||||
i = 1
|
||||
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
|
||||
"char", "byte", "bool", "openArray", "seq", "array", "void",
|
||||
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
|
||||
"cshort", "cu"]:
|
||||
result.add s[i]
|
||||
else:
|
||||
result.add toUpper(s[i])
|
||||
of skConst, skEnumField:
|
||||
# for 'const' we keep how it's spelt; either upper case or lower case:
|
||||
result.add s[0]
|
||||
else:
|
||||
# as a special rule, don't transform 'L' to 'l'
|
||||
if s.len == 1 and s[0] == 'L': result.add 'L'
|
||||
else: result.add toLower(s[0])
|
||||
inc i
|
||||
while i < s.len:
|
||||
if s[i] == '_':
|
||||
inc i
|
||||
result.add toUpper(s[i])
|
||||
elif allUpper:
|
||||
result.add toLower(s[i])
|
||||
else:
|
||||
result.add s[i]
|
||||
inc i
|
||||
|
||||
proc checkUse(c: PGen; n: PNode) =
|
||||
if n.info.fileIndex < 0: return
|
||||
let s = n.sym
|
||||
# operators stay as they are:
|
||||
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
|
||||
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
|
||||
if s.id in cannotRename: return
|
||||
|
||||
let newName = if rules.hasKey(s.name.s): rules[s.name.s]
|
||||
else: beautifyName(s.name.s, n.sym.kind)
|
||||
|
||||
loadFile(n.info)
|
||||
|
||||
let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
|
||||
var first = min(n.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
|
||||
|
||||
if {sfImportc, sfExportc} * s.flags != {}:
|
||||
# careful, we must ensure the resulting name still matches the external
|
||||
# name:
|
||||
if newName != s.name.s and newName != s.loc.r.ropeToStr and
|
||||
lfFullExternalName notin s.loc.flags:
|
||||
#Message(n.info, errGenerated,
|
||||
# "cannot rename $# to $# due to external name" % [s.name.s, newName])
|
||||
cannotRename.incl(s.id)
|
||||
return
|
||||
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)
|
||||
when removeTP:
|
||||
# the WinAPI module is full of 'TX = X' which after the substitution
|
||||
# becomes 'X = X'. We remove those lines:
|
||||
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
|
||||
x = ""
|
||||
|
||||
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
|
||||
gSourceFiles[n.info.fileIndex].dirty = true
|
||||
|
||||
proc check(c: PGen, n: PNode) =
|
||||
case n.kind
|
||||
of nkSym: checkUse(n, n.sym)
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
checkDef(c, n[0])
|
||||
check(c, n.sons[1])
|
||||
of nkForStmt, nkParForStmt:
|
||||
let L = n.len
|
||||
for i in countup(0, L-3):
|
||||
checkDef(c, n[i])
|
||||
check(c, n[L-2])
|
||||
check(c, n[L-1])
|
||||
of nkProcDef, nkLambdaKinds, nkMethodDef, nkIteratorDef, nkTemplateDef,
|
||||
nkMacroDef, nkConverterDef:
|
||||
checkDef(c, n[namePos])
|
||||
for i in namePos+1 .. <n.len: check(c, n.sons[i])
|
||||
of nkIdentDefs, nkVarTuple:
|
||||
let a = n
|
||||
checkMinSonsLen(a, 3)
|
||||
let L = len(a)
|
||||
for j in countup(0, L-3): checkDef(c, a.sons[j])
|
||||
check(c, a.sons[L-2])
|
||||
check(c, a.sons[L-1])
|
||||
of nkTypeSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
checkSonsLen(a, 3)
|
||||
checkDef(c, a.sons[0])
|
||||
check(c, a.sons[1])
|
||||
check(c, a.sons[2])
|
||||
else:
|
||||
for i in 0 .. <n.safeLen: check(c, n.sons[i])
|
||||
|
||||
proc processSym(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
check(PGen(c), n)
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
gCheckExtern = options.getConfigVar("pretty.checkextern").normalize == "on"
|
||||
result = g
|
||||
if rules.isNil:
|
||||
rules = newStringTable(modeStyleInsensitive)
|
||||
when removeTP:
|
||||
# XXX activate when the T/P stuff is deprecated
|
||||
let path = joinPath([getPrefixDir(), "config", "rename.rules.cfg"])
|
||||
for line in lines(path):
|
||||
if line.len > 0:
|
||||
let colon = line.find(':')
|
||||
if colon > 0:
|
||||
rules[line.substr(0, colon-1)] = line.substr(colon+1)
|
||||
else:
|
||||
rules[line] = line
|
||||
|
||||
const prettyPass* = makePass(open = myOpen, process = processSym)
|
||||
|
||||
@@ -17,52 +17,76 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
||||
if sonsLen(procA) != sonsLen(procB): return
|
||||
for i in countup(0, sonsLen(procA) - 1):
|
||||
if procA.sons[i].kind != nkSym:
|
||||
InternalError(procA.info, "equalGenericParams")
|
||||
internalError(procA.info, "equalGenericParams")
|
||||
return
|
||||
if procB.sons[i].kind != nkSym:
|
||||
InternalError(procB.info, "equalGenericParams")
|
||||
internalError(procB.info, "equalGenericParams")
|
||||
return
|
||||
let a = procA.sons[i].sym
|
||||
let b = procB.sons[i].sym
|
||||
if a.name.id != b.name.id or
|
||||
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
|
||||
not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
|
||||
if a.ast != nil and b.ast != nil:
|
||||
if not ExprStructuralEquivalent(a.ast, b.ast): return
|
||||
if not exprStructuralEquivalent(a.ast, b.ast): return
|
||||
result = true
|
||||
|
||||
proc SearchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
# Searchs for a forward declaration or a "twin" symbol of fn
|
||||
# in the symbol table. If the parameter lists are exactly
|
||||
# the same the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter
|
||||
result = initIdentIter(it, scope.symbols, fn.Name)
|
||||
result = initIdentIter(it, scope.symbols, fn.name)
|
||||
if isGenericRoutine(fn):
|
||||
# we simply check the AST; this is imprecise but nearly the best what
|
||||
# can be done; this doesn't work either though as type constraints are
|
||||
# not kept in the AST ..
|
||||
while result != nil:
|
||||
if result.Kind == fn.kind and isGenericRoutine(result):
|
||||
if result.kind == fn.kind and isGenericRoutine(result):
|
||||
let genR = result.ast.sons[genericParamsPos]
|
||||
let genF = fn.ast.sons[genericParamsPos]
|
||||
if ExprStructuralEquivalent(genR, genF) and
|
||||
ExprStructuralEquivalent(result.ast.sons[paramsPos],
|
||||
if exprStructuralEquivalent(genR, genF) and
|
||||
exprStructuralEquivalent(result.ast.sons[paramsPos],
|
||||
fn.ast.sons[paramsPos]) and
|
||||
equalGenericParams(genR, genF):
|
||||
return
|
||||
result = NextIdentIter(it, scope.symbols)
|
||||
result = nextIdentIter(it, scope.symbols)
|
||||
else:
|
||||
while result != nil:
|
||||
if result.Kind == fn.kind and not isGenericRoutine(result):
|
||||
if result.kind == fn.kind and not isGenericRoutine(result):
|
||||
case equalParams(result.typ.n, fn.typ.n)
|
||||
of paramsEqual:
|
||||
return
|
||||
of paramsIncompatible:
|
||||
LocalError(fn.info, errNotOverloadable, fn.name.s)
|
||||
localError(fn.info, errNotOverloadable, fn.name.s)
|
||||
return
|
||||
of paramsNotEqual:
|
||||
nil
|
||||
result = NextIdentIter(it, scope.symbols)
|
||||
discard
|
||||
result = nextIdentIter(it, scope.symbols)
|
||||
|
||||
proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
const flags = {ExactGenericParams, ExactTypeDescValues,
|
||||
ExactConstraints, IgnoreCC}
|
||||
|
||||
var it: TIdentIter
|
||||
result = initIdentIter(it, scope.symbols, fn.name)
|
||||
while result != nil:
|
||||
if result.kind in skProcKinds and
|
||||
sameType(result.typ, fn.typ, flags): return
|
||||
|
||||
result = nextIdentIter(it, scope.symbols)
|
||||
|
||||
return nil
|
||||
|
||||
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
result = searchForProcNew(c, scope, fn)
|
||||
when false:
|
||||
let old = searchForProcOld(c, scope, fn)
|
||||
if old != result:
|
||||
echo "Mismatch in searchForProc: ", fn.info
|
||||
debug fn.typ
|
||||
debug if result != nil: result.typ else: nil
|
||||
debug if old != nil: old.typ else: nil
|
||||
|
||||
when false:
|
||||
proc paramsFitBorrow(child, parent: PNode): bool =
|
||||
var length = sonsLen(child)
|
||||
@@ -77,7 +101,7 @@ when false:
|
||||
dcEqOrDistinctOf): return
|
||||
result = true
|
||||
|
||||
proc SearchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searchs for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
type
|
||||
TRenderFlag* = enum
|
||||
renderNone, renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderIds
|
||||
renderNoPragmas, renderIds, renderNoProcDefs
|
||||
TRenderFlags* = set[TRenderFlag]
|
||||
TRenderTok*{.final.} = object
|
||||
kind*: TTokType
|
||||
@@ -33,6 +33,7 @@ type
|
||||
# indentation value
|
||||
comStack*: seq[PNode] # comment stack
|
||||
flags*: TRenderFlags
|
||||
checkAnon: bool # we're in a context that can contain sfAnon
|
||||
|
||||
|
||||
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
|
||||
@@ -50,10 +51,17 @@ proc isKeyword*(s: string): bool =
|
||||
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
|
||||
result = true
|
||||
|
||||
proc renderDefinitionName*(s: PSym): string =
|
||||
proc renderDefinitionName*(s: PSym, noQuotes = false): string =
|
||||
## Returns the definition name of the symbol.
|
||||
##
|
||||
## If noQuotes is false the symbol may be returned in backticks. This will
|
||||
## happen if the name happens to be a keyword or the first character is not
|
||||
## part of the SymStartChars set.
|
||||
let x = s.name.s
|
||||
if x[0] in SymStartChars and not renderer.isKeyword(x): result = x
|
||||
else: result = '`' & x & '`'
|
||||
if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(x)):
|
||||
result = x
|
||||
else:
|
||||
result = '`' & x & '`'
|
||||
|
||||
const
|
||||
IndentWidth = 2
|
||||
@@ -61,7 +69,7 @@ const
|
||||
MaxLineLen = 80
|
||||
LineCommentColumn = 30
|
||||
|
||||
proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
||||
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
||||
g.comStack = @[]
|
||||
g.tokens = @[]
|
||||
g.indent = 0
|
||||
@@ -70,11 +78,12 @@ proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
||||
g.idx = 0
|
||||
g.buf = ""
|
||||
g.flags = renderFlags
|
||||
g.pendingNL = - 1
|
||||
g.pendingNL = -1
|
||||
g.checkAnon = false
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
var length = len(g.tokens)
|
||||
setlen(g.tokens, length + 1)
|
||||
setLen(g.tokens, length + 1)
|
||||
g.tokens[length].kind = kind
|
||||
g.tokens[length].length = int16(len(s))
|
||||
add(g.buf, s)
|
||||
@@ -102,16 +111,16 @@ proc optNL(g: var TSrcGen) =
|
||||
optNL(g, g.indent)
|
||||
|
||||
proc indentNL(g: var TSrcGen) =
|
||||
inc(g.indent, indentWidth)
|
||||
inc(g.indent, IndentWidth)
|
||||
g.pendingNL = g.indent
|
||||
g.lineLen = g.indent
|
||||
|
||||
proc Dedent(g: var TSrcGen) =
|
||||
dec(g.indent, indentWidth)
|
||||
proc dedent(g: var TSrcGen) =
|
||||
dec(g.indent, IndentWidth)
|
||||
assert(g.indent >= 0)
|
||||
if g.pendingNL > indentWidth:
|
||||
Dec(g.pendingNL, indentWidth)
|
||||
Dec(g.lineLen, indentWidth)
|
||||
if g.pendingNL > IndentWidth:
|
||||
dec(g.pendingNL, IndentWidth)
|
||||
dec(g.lineLen, IndentWidth)
|
||||
|
||||
proc put(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
addPendingNL(g)
|
||||
@@ -125,7 +134,7 @@ proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
|
||||
addTok(g, kind, s)
|
||||
g.lineLen = lineLen
|
||||
|
||||
proc toNimChar(c: Char): string =
|
||||
proc toNimChar(c: char): string =
|
||||
case c
|
||||
of '\0': result = "\\0"
|
||||
of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
|
||||
@@ -234,19 +243,19 @@ proc containsNL(s: string): bool =
|
||||
of '\x0D', '\x0A':
|
||||
return true
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
result = false
|
||||
|
||||
proc pushCom(g: var TSrcGen, n: PNode) =
|
||||
var length = len(g.comStack)
|
||||
setlen(g.comStack, length + 1)
|
||||
setLen(g.comStack, length + 1)
|
||||
g.comStack[length] = n
|
||||
|
||||
proc popAllComs(g: var TSrcGen) =
|
||||
setlen(g.comStack, 0)
|
||||
setLen(g.comStack, 0)
|
||||
|
||||
proc popCom(g: var TSrcGen) =
|
||||
setlen(g.comStack, len(g.comStack) - 1)
|
||||
setLen(g.comStack, len(g.comStack) - 1)
|
||||
|
||||
const
|
||||
Space = " "
|
||||
@@ -267,7 +276,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
|
||||
if (g.pendingNL < 0) and (len(g.buf) > 0) and
|
||||
(g.lineLen < LineCommentColumn):
|
||||
var ml = maxLineLength(n.comment)
|
||||
if ml + LineCommentColumn <= maxLineLen:
|
||||
if ml + LineCommentColumn <= MaxLineLen:
|
||||
put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
|
||||
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
||||
|
||||
@@ -276,7 +285,7 @@ proc gcoms(g: var TSrcGen) =
|
||||
popAllComs(g)
|
||||
|
||||
proc lsub(n: PNode): int
|
||||
proc litAux(n: PNode, x: biggestInt, size: int): string =
|
||||
proc litAux(n: PNode, x: BiggestInt, size: int): string =
|
||||
proc skip(t: PType): PType =
|
||||
result = t
|
||||
while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||
@@ -293,7 +302,7 @@ proc litAux(n: PNode, x: biggestInt, size: int): string =
|
||||
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
|
||||
else: result = $x
|
||||
|
||||
proc ulitAux(n: PNode, x: biggestInt, size: int): string =
|
||||
proc ulitAux(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)
|
||||
@@ -327,7 +336,7 @@ proc atom(n: PNode): string =
|
||||
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
|
||||
result = $n.floatVal & "\'f32"
|
||||
else:
|
||||
f = n.floatVal
|
||||
f = n.floatVal.float32
|
||||
result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
|
||||
of nkFloat64Lit:
|
||||
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
|
||||
@@ -339,7 +348,7 @@ proc atom(n: PNode): string =
|
||||
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
|
||||
else: result = "[type node]"
|
||||
else:
|
||||
InternalError("rnimsyn.atom " & $n.kind)
|
||||
internalError("rnimsyn.atom " & $n.kind)
|
||||
result = ""
|
||||
|
||||
proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
@@ -359,11 +368,11 @@ proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
proc lsub(n: PNode): int =
|
||||
# computes the length of a tree
|
||||
if isNil(n): return 0
|
||||
if n.comment != nil: return maxLineLen + 1
|
||||
if n.comment != nil: return MaxLineLen + 1
|
||||
case n.kind
|
||||
of nkEmpty: result = 0
|
||||
of nkTripleStrLit:
|
||||
if containsNL(n.strVal): result = maxLineLen + 1
|
||||
if containsNL(n.strVal): result = MaxLineLen + 1
|
||||
else: result = len(atom(n))
|
||||
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
|
||||
result = len(atom(n))
|
||||
@@ -405,7 +414,8 @@ proc lsub(n: PNode): int =
|
||||
result = result + lcomma(n, 1)
|
||||
of nkExprColonExpr: result = lsons(n) + 2
|
||||
of nkInfix: result = lsons(n) + 2
|
||||
of nkPrefix: result = lsons(n) + 1
|
||||
of nkPrefix:
|
||||
result = lsons(n)+1+(if n.len > 0 and n.sons[1].kind == nkInfix: 2 else: 0)
|
||||
of nkPostfix: result = lsons(n)
|
||||
of nkCallStrLit: result = lsons(n)
|
||||
of nkPragmaExpr: result = lsub(n.sons[0]) + lcomma(n, 1)
|
||||
@@ -418,10 +428,16 @@ proc lsub(n: PNode): int =
|
||||
of nkElifExpr: result = lsons(n) + len("_elif_:_")
|
||||
of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions
|
||||
of nkTypeOfExpr: result = lsub(n.sons[0]) + len("type_")
|
||||
of nkRefTy: result = lsub(n.sons[0]) + len("ref_")
|
||||
of nkPtrTy: result = lsub(n.sons[0]) + len("ptr_")
|
||||
of nkVarTy: result = lsub(n.sons[0]) + len("var_")
|
||||
of nkDistinctTy: result = lsub(n.sons[0]) + len("Distinct_")
|
||||
of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
|
||||
of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
|
||||
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
|
||||
of nkDistinctTy:
|
||||
result = len("distinct") + (if n.len > 0: lsub(n.sons[0])+1 else: 0)
|
||||
if n.len > 1:
|
||||
result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
|
||||
result += lcomma(n[1])
|
||||
of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
|
||||
len("static[]")
|
||||
of nkTypeDef: result = lsons(n) + 3
|
||||
of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
|
||||
of nkProcTy: result = lsons(n) + len("proc_")
|
||||
@@ -434,7 +450,7 @@ proc lsub(n: PNode): int =
|
||||
result = len("enum")
|
||||
of nkEnumFieldDef: result = lsons(n) + 3
|
||||
of nkVarSection, nkLetSection:
|
||||
if sonsLen(n) > 1: result = maxLineLen + 1
|
||||
if sonsLen(n) > 1: result = MaxLineLen + 1
|
||||
else: result = lsons(n) + len("var_")
|
||||
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
|
||||
of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
|
||||
@@ -445,6 +461,7 @@ proc lsub(n: PNode): int =
|
||||
of nkPragma: result = lcomma(n) + 4
|
||||
of nkCommentStmt: result = len(n.comment)
|
||||
of nkOfBranch: result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_")
|
||||
of nkImportAs: result = lsub(n.sons[0]) + len("_as_") + lsub(n.sons[1])
|
||||
of nkElifBranch: result = lsons(n) + len("elif_:_")
|
||||
of nkElse: result = lsub(n.sons[0]) + len("else:_")
|
||||
of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
|
||||
@@ -454,10 +471,10 @@ proc lsub(n: PNode): int =
|
||||
if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
|
||||
of nkExceptBranch:
|
||||
result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
|
||||
else: result = maxLineLen + 1
|
||||
else: result = MaxLineLen + 1
|
||||
|
||||
proc fits(g: TSrcGen, x: int): bool =
|
||||
result = x + g.lineLen <= maxLineLen
|
||||
result = x + g.lineLen <= MaxLineLen
|
||||
|
||||
type
|
||||
TSubFlag = enum
|
||||
@@ -482,7 +499,7 @@ proc hasCom(n: PNode): bool =
|
||||
result = false
|
||||
if n.comment != nil: return true
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: nil
|
||||
of nkEmpty..nkNilLit: discard
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if hasCom(n.sons[i]): return true
|
||||
@@ -493,13 +510,15 @@ 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 countup(start, sonsLen(n) + theEnd):
|
||||
for i in countup(start, sonsLen(n) + theEnd):
|
||||
var c = i < sonsLen(n) + theEnd
|
||||
var sublen = lsub(n.sons[i]) + ord(c)
|
||||
if not fits(g, sublen) and (ind + sublen < maxLineLen): optNL(g, ind)
|
||||
if not fits(g, sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
|
||||
let oldLen = g.tokens.len
|
||||
gsub(g, n.sons[i])
|
||||
if c:
|
||||
putWithSpace(g, separator, TokTypeToStr[separator])
|
||||
if c:
|
||||
if g.tokens.len > oldLen:
|
||||
putWithSpace(g, separator, TokTypeToStr[separator])
|
||||
if hasCom(n.sons[i]):
|
||||
gcoms(g)
|
||||
optNL(g, ind)
|
||||
@@ -508,21 +527,21 @@ proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
|
||||
theEnd: int = - 1) =
|
||||
var ind: int
|
||||
if rfInConstExpr in c.flags:
|
||||
ind = g.indent + indentWidth
|
||||
ind = g.indent + IndentWidth
|
||||
else:
|
||||
ind = g.lineLen
|
||||
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
|
||||
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
|
||||
gcommaAux(g, n, ind, start, theEnd)
|
||||
|
||||
proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
|
||||
var ind = g.lineLen
|
||||
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
|
||||
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
|
||||
gcommaAux(g, n, ind, start, theEnd)
|
||||
|
||||
proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
|
||||
var ind = g.lineLen
|
||||
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
|
||||
gcommaAux(g, n, ind, start, theEnd, tkSemicolon)
|
||||
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
|
||||
gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
|
||||
|
||||
proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
|
||||
theEnd: int = - 1) =
|
||||
@@ -545,20 +564,23 @@ proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
|
||||
if not result:
|
||||
# check further
|
||||
for i in countup(start, sonsLen(n) + theEnd):
|
||||
if (lsub(n.sons[i]) > maxLineLen):
|
||||
if (lsub(n.sons[i]) > MaxLineLen):
|
||||
result = true
|
||||
break
|
||||
|
||||
proc gstmts(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
if n.kind == nkEmpty: return
|
||||
if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr):
|
||||
indentNL(g)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
|
||||
if n.kind == nkEmpty: return
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
|
||||
if doIndent: indentNL(g)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
optNL(g)
|
||||
gsub(g, n.sons[i])
|
||||
if n.sons[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
|
||||
gstmts(g, n.sons[i], c, doIndent=false)
|
||||
else:
|
||||
gsub(g, n.sons[i])
|
||||
gcoms(g)
|
||||
dedent(g)
|
||||
else:
|
||||
if doIndent: dedent(g)
|
||||
else:
|
||||
if rfLongMode in c.flags: indentNL(g)
|
||||
gsub(g, n)
|
||||
gcoms(g)
|
||||
@@ -570,7 +592,7 @@ proc gif(g: var TSrcGen, n: PNode) =
|
||||
gsub(g, n.sons[0].sons[0])
|
||||
initContext(c)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[0].sons[1], c)
|
||||
@@ -585,7 +607,7 @@ proc gwhile(g: var TSrcGen, n: PNode) =
|
||||
gsub(g, n.sons[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[1], c)
|
||||
@@ -594,7 +616,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
put(g, tkCurlyLe, "{")
|
||||
initContext(c)
|
||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[0], c)
|
||||
@@ -605,7 +627,7 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) =
|
||||
gsub(g, n.sons[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[1], c)
|
||||
@@ -615,7 +637,7 @@ proc gtry(g: var TSrcGen, n: PNode) =
|
||||
put(g, tkTry, "try")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[0], c)
|
||||
@@ -628,7 +650,7 @@ proc gfor(g: var TSrcGen, n: PNode) =
|
||||
initContext(c)
|
||||
if longMode(n) or
|
||||
(lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
|
||||
maxLineLen):
|
||||
MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcomma(g, n, c, 0, - 3)
|
||||
put(g, tkSpaces, Space)
|
||||
@@ -643,7 +665,7 @@ proc gmacro(g: var TSrcGen, n: PNode) =
|
||||
initContext(c)
|
||||
gsub(g, n.sons[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g)
|
||||
gsons(g, n, c, 1)
|
||||
@@ -673,7 +695,10 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
gpattern(g, n.sons[patternPos])
|
||||
let oldCheckAnon = g.checkAnon
|
||||
g.checkAnon = true
|
||||
gsub(g, n.sons[genericParamsPos])
|
||||
g.checkAnon = oldCheckAnon
|
||||
gsub(g, n.sons[paramsPos])
|
||||
gsub(g, n.sons[pragmasPos])
|
||||
if renderNoBody notin g.flags:
|
||||
@@ -691,6 +716,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
gcoms(g)
|
||||
dedent(g)
|
||||
|
||||
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
putWithSpace(g, tkGeneric, "generic")
|
||||
gsons(g, n[0], c) # arglist
|
||||
gsub(g, n[1]) # pragmas
|
||||
gsub(g, n[2]) # of
|
||||
gcoms(g)
|
||||
indentNL(g)
|
||||
gcoms(g)
|
||||
gstmts(g, n[3], c)
|
||||
dedent(g)
|
||||
|
||||
proc gblock(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
@@ -700,7 +738,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
|
||||
else:
|
||||
put(g, tkBlock, "block")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g)
|
||||
# XXX I don't get why this is needed here! gstmts should already handle this!
|
||||
@@ -713,7 +751,7 @@ proc gstaticStmt(g: var TSrcGen, n: PNode) =
|
||||
putWithSpace(g, tkStatic, "static")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
|
||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[0], c)
|
||||
@@ -724,7 +762,8 @@ proc gasm(g: var TSrcGen, n: PNode) =
|
||||
gcoms(g)
|
||||
gsub(g, n.sons[1])
|
||||
|
||||
proc gident(g: var TSrcGen, n: PNode) =
|
||||
proc gident(g: var TSrcGen, n: PNode) =
|
||||
if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
|
||||
var t: TTokType
|
||||
var s = atom(n)
|
||||
if (s[0] in lexer.SymChars):
|
||||
@@ -758,7 +797,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
if n.comment != nil: pushCom(g, n)
|
||||
case n.kind # atoms:
|
||||
of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal)
|
||||
of nkEmpty: nil
|
||||
of nkEmpty: discard
|
||||
of nkType: put(g, tkInvalid, atom(n))
|
||||
of nkSym, nkIdent: gident(g, n)
|
||||
of nkIntLit: put(g, tkIntLit, atom(n))
|
||||
@@ -806,7 +845,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkParRi, ")")
|
||||
of nkStaticExpr:
|
||||
put(g, tkStatic, "static")
|
||||
put(g, tkSpaces, space)
|
||||
put(g, tkSpaces, Space)
|
||||
gsub(g, n.sons[0])
|
||||
of nkBracketExpr:
|
||||
gsub(g, n.sons[0])
|
||||
@@ -823,7 +862,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gcomma(g, n, 1)
|
||||
of nkCommand:
|
||||
gsub(g, n.sons[0])
|
||||
put(g, tkSpaces, space)
|
||||
put(g, tkSpaces, Space)
|
||||
gcomma(g, n, 1)
|
||||
of nkExprEqExpr, nkAsgn, nkFastAsgn:
|
||||
gsub(g, n.sons[0])
|
||||
@@ -897,8 +936,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gsub(g, n.sons[pragmasPos])
|
||||
put(g, tkColon, ":")
|
||||
gsub(g, n.sons[bodyPos])
|
||||
of nkConstDef, nkIdentDefs:
|
||||
gcomma(g, n, 0, - 3)
|
||||
of nkConstDef, nkIdentDefs:
|
||||
gcomma(g, n, 0, -3)
|
||||
var L = sonsLen(n)
|
||||
if n.sons[L - 2].kind != nkEmpty:
|
||||
putWithSpace(g, tkColon, ":")
|
||||
@@ -909,7 +948,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gsub(g, n.sons[L - 1], c)
|
||||
of nkVarTuple:
|
||||
put(g, tkParLe, "(")
|
||||
gcomma(g, n, 0, - 3)
|
||||
gcomma(g, n, 0, -3)
|
||||
put(g, tkParRi, ")")
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
@@ -930,8 +969,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
of nkPrefix:
|
||||
gsub(g, n.sons[0])
|
||||
if n.len > 1:
|
||||
put(g, tkSpaces, space)
|
||||
gsub(g, n.sons[1])
|
||||
put(g, tkSpaces, Space)
|
||||
if n.sons[1].kind == nkInfix:
|
||||
put(g, tkParLe, "(")
|
||||
gsub(g, n.sons[1])
|
||||
put(g, tkParRi, ")")
|
||||
else:
|
||||
gsub(g, n.sons[1])
|
||||
of nkPostfix:
|
||||
gsub(g, n.sons[1])
|
||||
gsub(g, n.sons[0])
|
||||
@@ -986,9 +1030,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
else:
|
||||
put(g, tkVar, "var")
|
||||
of nkDistinctTy:
|
||||
if sonsLen(n) > 0:
|
||||
if n.len > 0:
|
||||
putWithSpace(g, tkDistinct, "distinct")
|
||||
gsub(g, n.sons[0])
|
||||
if n.len > 1:
|
||||
if n[1].kind == nkWith:
|
||||
putWithSpace(g, tkWith, " with")
|
||||
else:
|
||||
putWithSpace(g, tkWithout, " without")
|
||||
gcomma(g, n[1])
|
||||
else:
|
||||
put(g, tkDistinct, "distinct")
|
||||
of nkTypeDef:
|
||||
@@ -1032,12 +1082,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gsub(g, n.sons[1])
|
||||
else:
|
||||
put(g, tkIterator, "iterator")
|
||||
of nkSharedTy:
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkShared, "shared")
|
||||
of nkStaticTy:
|
||||
put(g, tkStatic, "static")
|
||||
put(g, tkBracketLe, "[")
|
||||
if n.len > 0:
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkShared, "shared")
|
||||
put(g, tkBracketRi, "]")
|
||||
of nkEnumTy:
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkEnum, "enum")
|
||||
@@ -1054,7 +1104,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
gsub(g, n.sons[1])
|
||||
of nkStmtList, nkStmtListExpr: gstmts(g, n, emptyContext)
|
||||
of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
|
||||
of nkIfStmt:
|
||||
putWithSpace(g, tkIf, "if")
|
||||
gif(g, n)
|
||||
@@ -1070,22 +1120,22 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
of nkStaticStmt: gstaticStmt(g, n)
|
||||
of nkAsmStmt: gasm(g, n)
|
||||
of nkProcDef:
|
||||
putWithSpace(g, tkProc, "proc")
|
||||
if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
|
||||
gproc(g, n)
|
||||
of nkConverterDef:
|
||||
putWithSpace(g, tkConverter, "converter")
|
||||
if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
|
||||
gproc(g, n)
|
||||
of nkMethodDef:
|
||||
putWithSpace(g, tkMethod, "method")
|
||||
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
|
||||
gproc(g, n)
|
||||
of nkIteratorDef:
|
||||
putWithSpace(g, tkIterator, "iterator")
|
||||
if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
|
||||
gproc(g, n)
|
||||
of nkMacroDef:
|
||||
putWithSpace(g, tkMacro, "macro")
|
||||
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
|
||||
gproc(g, n)
|
||||
of nkTemplateDef:
|
||||
putWithSpace(g, tkTemplate, "template")
|
||||
if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
|
||||
gproc(g, n)
|
||||
of nkTypeSection:
|
||||
gsection(g, n, emptyContext, tkType, "type")
|
||||
@@ -1177,6 +1227,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gcoms(g)
|
||||
gstmts(g, lastSon(n), c)
|
||||
of nkImportAs:
|
||||
gsub(g, n.sons[0])
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkAs, "as")
|
||||
gsub(g, n.sons[1])
|
||||
of nkBindStmt:
|
||||
putWithSpace(g, tkBind, "bind")
|
||||
gcomma(g, n, c)
|
||||
@@ -1226,9 +1281,20 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
of nkMetaNode_Obsolete:
|
||||
put(g, tkParLe, "(META|")
|
||||
gsub(g, n.sons[0])
|
||||
put(g, tkParRi, ")")
|
||||
of nkGotoState, nkState:
|
||||
var c: TContext
|
||||
initContext c
|
||||
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
|
||||
gsons(g, n, c)
|
||||
of nkTypeClassTy:
|
||||
gTypeClassTy(g, n)
|
||||
else:
|
||||
#nkNone, nkMetaNode, nkExplicitTypeListCall:
|
||||
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||
#nkNone, nkExplicitTypeListCall:
|
||||
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||
|
||||
proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||
var g: TSrcGen
|
||||
@@ -1239,7 +1305,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||
proc renderModule(n: PNode, filename: string,
|
||||
renderFlags: TRenderFlags = {}) =
|
||||
var
|
||||
f: tfile
|
||||
f: TFile
|
||||
g: TSrcGen
|
||||
initSrcGen(g, renderFlags)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
@@ -1248,7 +1314,7 @@ proc renderModule(n: PNode, filename: string,
|
||||
case n.sons[i].kind
|
||||
of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
|
||||
nkCommentStmt: putNL(g)
|
||||
else: nil
|
||||
else: discard
|
||||
gcoms(g)
|
||||
if optStdout in gGlobalOptions:
|
||||
write(stdout, g.buf)
|
||||
@@ -1271,4 +1337,3 @@ proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
|
||||
inc(r.idx)
|
||||
else:
|
||||
kind = tkEof
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ type
|
||||
memfile: TMemFile # unfortunately there is no point in time where we
|
||||
# can close this! XXX
|
||||
methods*: TSymSeq
|
||||
origFile: string
|
||||
inViewMode: bool
|
||||
|
||||
PRodReader* = ref TRodReader
|
||||
@@ -183,7 +184,7 @@ proc skipNode(r: PRodReader) =
|
||||
if par == 0: break
|
||||
dec par
|
||||
of '(': inc par
|
||||
else: nil
|
||||
else: discard
|
||||
inc pos
|
||||
r.pos = pos+1 # skip ')'
|
||||
|
||||
@@ -247,7 +248,7 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
|
||||
if r.s[r.pos] == ')': inc(r.pos)
|
||||
else: internalError(result.info, "decodeNode: ')' missing")
|
||||
else:
|
||||
InternalError(fInfo, "decodeNode: '(' missing " & $r.pos)
|
||||
internalError(fInfo, "decodeNode: '(' missing " & $r.pos)
|
||||
|
||||
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||
result = decodeNodeLazyBody(r, fInfo, nil)
|
||||
@@ -285,7 +286,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
|
||||
else:
|
||||
loc.a = 0
|
||||
if r.s[r.pos] == '>': inc(r.pos)
|
||||
else: InternalError(info, "decodeLoc " & r.s[r.pos])
|
||||
else: internalError(info, "decodeLoc " & r.s[r.pos])
|
||||
|
||||
proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||
result = nil
|
||||
@@ -302,10 +303,10 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||
setId(result.id)
|
||||
if debugIds: registerID(result)
|
||||
else:
|
||||
InternalError(info, "decodeType: no id")
|
||||
internalError(info, "decodeType: no id")
|
||||
# here this also avoids endless recursion for recursive type
|
||||
IdTablePut(gTypeTable, result, result)
|
||||
if r.s[r.pos] == '(': result.n = decodeNode(r, UnknownLineInfo())
|
||||
idTablePut(gTypeTable, result, result)
|
||||
if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
|
||||
if r.s[r.pos] == '$':
|
||||
inc(r.pos)
|
||||
result.flags = cast[TTypeFlags](int32(decodeVInt(r.s, r.pos)))
|
||||
@@ -334,7 +335,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||
if r.s[r.pos] == '(':
|
||||
inc(r.pos)
|
||||
if r.s[r.pos] == ')': inc(r.pos)
|
||||
else: InternalError(info, "decodeType ^(" & r.s[r.pos])
|
||||
else: internalError(info, "decodeType ^(" & r.s[r.pos])
|
||||
rawAddSon(result, nil)
|
||||
else:
|
||||
var d = decodeVInt(r.s, r.pos)
|
||||
@@ -346,10 +347,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
|
||||
new(result)
|
||||
inc(r.pos)
|
||||
result.kind = TLibKind(decodeVInt(r.s, r.pos))
|
||||
if r.s[r.pos] != '|': InternalError("decodeLib: 1")
|
||||
if r.s[r.pos] != '|': internalError("decodeLib: 1")
|
||||
inc(r.pos)
|
||||
result.name = toRope(decodeStr(r.s, r.pos))
|
||||
if r.s[r.pos] != '|': InternalError("decodeLib: 2")
|
||||
if r.s[r.pos] != '|': internalError("decodeLib: 2")
|
||||
inc(r.pos)
|
||||
result.path = decodeNode(r, info)
|
||||
|
||||
@@ -369,21 +370,21 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||
id = decodeVInt(r.s, r.pos)
|
||||
setId(id)
|
||||
else:
|
||||
InternalError(info, "decodeSym: no id")
|
||||
internalError(info, "decodeSym: no id")
|
||||
if r.s[r.pos] == '&':
|
||||
inc(r.pos)
|
||||
ident = getIdent(decodeStr(r.s, r.pos))
|
||||
else:
|
||||
InternalError(info, "decodeSym: no ident")
|
||||
internalError(info, "decodeSym: no ident")
|
||||
#echo "decoding: {", ident.s
|
||||
result = PSym(IdTableGet(r.syms, id))
|
||||
result = PSym(idTableGet(r.syms, id))
|
||||
if result == nil:
|
||||
new(result)
|
||||
result.id = id
|
||||
IdTablePut(r.syms, result, result)
|
||||
idTablePut(r.syms, result, result)
|
||||
if debugIds: registerID(result)
|
||||
elif result.id != id:
|
||||
InternalError(info, "decodeSym: wrong id")
|
||||
internalError(info, "decodeSym: wrong id")
|
||||
elif result.kind != skStub and not r.inViewMode:
|
||||
# we already loaded the symbol
|
||||
return
|
||||
@@ -426,7 +427,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||
result.annex = decodeLib(r, info)
|
||||
if r.s[r.pos] == '#':
|
||||
inc(r.pos)
|
||||
result.constraint = decodeNode(r, UnknownLineInfo())
|
||||
result.constraint = decodeNode(r, unknownLineInfo())
|
||||
if r.s[r.pos] == '(':
|
||||
if result.kind in routineKinds:
|
||||
result.ast = decodeNodeLazyBody(r, result.info, result)
|
||||
@@ -454,10 +455,10 @@ proc skipSection(r: PRodReader) =
|
||||
elif c > 0:
|
||||
dec(c)
|
||||
of '\0': break # end of file
|
||||
else: nil
|
||||
else: discard
|
||||
inc(r.pos)
|
||||
else:
|
||||
InternalError("skipSection " & $r.line)
|
||||
internalError("skipSection " & $r.line)
|
||||
|
||||
proc rdWord(r: PRodReader): string =
|
||||
result = ""
|
||||
@@ -471,11 +472,11 @@ proc newStub(r: PRodReader, name: string, id: int): PSym =
|
||||
result.id = id
|
||||
result.name = getIdent(name)
|
||||
result.position = r.readerIndex
|
||||
setID(id) #MessageOut(result.name.s);
|
||||
setId(id) #MessageOut(result.name.s);
|
||||
if debugIds: registerID(result)
|
||||
|
||||
proc processInterf(r: PRodReader, module: PSym) =
|
||||
if r.interfIdx == 0: InternalError("processInterf")
|
||||
if r.interfIdx == 0: internalError("processInterf")
|
||||
r.pos = r.interfIdx
|
||||
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
|
||||
var w = decodeStr(r.s, r.pos)
|
||||
@@ -484,23 +485,23 @@ proc processInterf(r: PRodReader, module: PSym) =
|
||||
inc(r.pos) # #10
|
||||
var s = newStub(r, w, key)
|
||||
s.owner = module
|
||||
StrTableAdd(module.tab, s)
|
||||
IdTablePut(r.syms, s, s)
|
||||
strTableAdd(module.tab, s)
|
||||
idTablePut(r.syms, s, s)
|
||||
|
||||
proc processCompilerProcs(r: PRodReader, module: PSym) =
|
||||
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
|
||||
if r.compilerProcsIdx == 0: internalError("processCompilerProcs")
|
||||
r.pos = r.compilerProcsIdx
|
||||
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
|
||||
var w = decodeStr(r.s, r.pos)
|
||||
inc(r.pos)
|
||||
var key = decodeVInt(r.s, r.pos)
|
||||
inc(r.pos) # #10
|
||||
var s = PSym(IdTableGet(r.syms, key))
|
||||
var s = PSym(idTableGet(r.syms, key))
|
||||
if s == nil:
|
||||
s = newStub(r, w, key)
|
||||
s.owner = module
|
||||
IdTablePut(r.syms, s, s)
|
||||
StrTableAdd(rodCompilerProcs, s)
|
||||
idTablePut(r.syms, s, s)
|
||||
strTableAdd(rodCompilerprocs, s)
|
||||
|
||||
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
|
||||
var key, val, tmp: int
|
||||
@@ -515,11 +516,11 @@ proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
|
||||
else:
|
||||
key = idx.lastIdxKey + 1
|
||||
val = tmp + idx.lastIdxVal
|
||||
IITablePut(idx.tab, key, val)
|
||||
iiTablePut(idx.tab, key, val)
|
||||
if not outf.isNil: outf.write(key, " ", val, "\n")
|
||||
idx.lastIdxKey = key
|
||||
idx.lastIdxVal = val
|
||||
setID(key) # ensure that this id will not be used
|
||||
setId(key) # ensure that this id will not be used
|
||||
if r.s[r.pos] == '\x0A':
|
||||
inc(r.pos)
|
||||
inc(r.line)
|
||||
@@ -538,7 +539,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
|
||||
of cmdNone, cmdDoc, cmdInterpret, cmdPretty, cmdGenDepend, cmdDump,
|
||||
cmdCheck, cmdParse, cmdScan, cmdIdeTools, cmdDef,
|
||||
cmdRst2html, cmdRst2tex, cmdInteractive, cmdRun:
|
||||
nil
|
||||
discard
|
||||
# else: trigger recompilation:
|
||||
result = true
|
||||
|
||||
@@ -557,7 +558,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
of "ID":
|
||||
inc(r.pos) # skip ':'
|
||||
r.moduleID = decodeVInt(r.s, r.pos)
|
||||
setID(r.moduleID)
|
||||
setId(r.moduleID)
|
||||
of "ORIGFILE":
|
||||
inc(r.pos)
|
||||
r.origFile = decodeStr(r.s, r.pos)
|
||||
of "OPTIONS":
|
||||
inc(r.pos) # skip ':'
|
||||
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
|
||||
@@ -585,7 +589,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
inc(r.line)
|
||||
while r.s[r.pos] != ')':
|
||||
let relativePath = decodeStr(r.s, r.pos)
|
||||
let resolvedPath = relativePath.findModule
|
||||
let resolvedPath = relativePath.findModule(r.origFile)
|
||||
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
|
||||
r.files.add(finalPath.fileInfoIdx)
|
||||
inc(r.pos) # skip #10
|
||||
@@ -599,7 +603,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
inc(r.pos) # skip ' '
|
||||
inclCrc = decodeVInt(r.s, r.pos)
|
||||
if r.reason == rrNone:
|
||||
if not ExistsFile(w) or (inclCrc != int(crcFromFile(w))):
|
||||
if not existsFile(w) or (inclCrc != int(crcFromFile(w))):
|
||||
r.reason = rrInclDeps
|
||||
if r.s[r.pos] == '\x0A':
|
||||
inc(r.pos)
|
||||
@@ -635,7 +639,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
r.initIdx = r.pos + 2 # "(\10"
|
||||
skipSection(r)
|
||||
else:
|
||||
InternalError("invalid section: '" & section &
|
||||
internalError("invalid section: '" & section &
|
||||
"' at " & $r.line & " in " & r.filename)
|
||||
#MsgWriteln("skipping section: " & section &
|
||||
# " at " & $r.line & " in " & r.filename)
|
||||
@@ -654,7 +658,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||
readerIndex: int): PRodReader =
|
||||
new(result)
|
||||
try:
|
||||
result.memFile = memfiles.open(modfilename)
|
||||
result.memfile = memfiles.open(modfilename)
|
||||
except EOS:
|
||||
return nil
|
||||
result.files = @[]
|
||||
@@ -666,13 +670,13 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||
r.line = 1
|
||||
r.readerIndex = readerIndex
|
||||
r.filename = modfilename
|
||||
InitIdTable(r.syms)
|
||||
initIdTable(r.syms)
|
||||
# we terminate the file explicitely with ``\0``, so the cast to `cstring`
|
||||
# is safe:
|
||||
r.s = cast[cstring](r.memFile.mem)
|
||||
r.s = cast[cstring](r.memfile.mem)
|
||||
if startsWith(r.s, "NIM:"):
|
||||
initIITable(r.index.tab)
|
||||
initIITable(r.imports.tab) # looks like a ROD file
|
||||
initIiTable(r.index.tab)
|
||||
initIiTable(r.imports.tab) # looks like a ROD file
|
||||
inc(r.pos, 4)
|
||||
var version = ""
|
||||
while r.s[r.pos] notin {'\0', '\x0A'}:
|
||||
@@ -687,12 +691,12 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||
result = nil
|
||||
|
||||
proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType =
|
||||
result = PType(IdTableGet(gTypeTable, id))
|
||||
result = PType(idTableGet(gTypeTable, id))
|
||||
if result == nil:
|
||||
# load the type:
|
||||
var oldPos = r.pos
|
||||
var d = IITableGet(r.index.tab, id)
|
||||
if d == invalidKey: InternalError(info, "rrGetType")
|
||||
var d = iiTableGet(r.index.tab, id)
|
||||
if d == InvalidKey: internalError(info, "rrGetType")
|
||||
r.pos = d + r.dataIdx
|
||||
result = decodeType(r, info)
|
||||
r.pos = oldPos
|
||||
@@ -711,7 +715,7 @@ var gMods*: TFileModuleMap = @[]
|
||||
|
||||
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
|
||||
# all compiled modules
|
||||
if rd.dataIdx == 0: InternalError(info, "dataIdx == 0")
|
||||
if rd.dataIdx == 0: internalError(info, "dataIdx == 0")
|
||||
var oldPos = rd.pos
|
||||
rd.pos = offset + rd.dataIdx
|
||||
result = decodeSym(rd, info)
|
||||
@@ -721,8 +725,8 @@ proc findSomeWhere(id: int) =
|
||||
for i in countup(0, high(gMods)):
|
||||
var rd = gMods[i].rd
|
||||
if rd != nil:
|
||||
var d = IITableGet(rd.index.tab, id)
|
||||
if d != invalidKey:
|
||||
var d = iiTableGet(rd.index.tab, id)
|
||||
if d != InvalidKey:
|
||||
echo "found id ", id, " in ", gMods[i].filename
|
||||
|
||||
proc getReader(moduleId: int): PRodReader =
|
||||
@@ -732,37 +736,37 @@ proc getReader(moduleId: int): PRodReader =
|
||||
# problems:
|
||||
for i in 0 .. <gMods.len:
|
||||
result = gMods[i].rd
|
||||
if result != nil and result.moduleId == moduleId: return result
|
||||
if result != nil and result.moduleID == moduleId: return result
|
||||
return nil
|
||||
|
||||
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||
result = PSym(IdTableGet(r.syms, id))
|
||||
result = PSym(idTableGet(r.syms, id))
|
||||
if result == nil:
|
||||
# load the symbol:
|
||||
var d = IITableGet(r.index.tab, id)
|
||||
if d == invalidKey:
|
||||
var d = iiTableGet(r.index.tab, id)
|
||||
if d == InvalidKey:
|
||||
# import from other module:
|
||||
var moduleID = IiTableGet(r.imports.tab, id)
|
||||
var moduleID = iiTableGet(r.imports.tab, id)
|
||||
if moduleID < 0:
|
||||
var x = ""
|
||||
encodeVInt(id, x)
|
||||
InternalError(info, "missing from both indexes: +" & x)
|
||||
internalError(info, "missing from both indexes: +" & x)
|
||||
var rd = getReader(moduleID)
|
||||
d = IITableGet(rd.index.tab, id)
|
||||
if d != invalidKey:
|
||||
d = iiTableGet(rd.index.tab, id)
|
||||
if d != InvalidKey:
|
||||
result = decodeSymSafePos(rd, d, info)
|
||||
else:
|
||||
var x = ""
|
||||
encodeVInt(id, x)
|
||||
when false: findSomeWhere(id)
|
||||
InternalError(info, "rrGetSym: no reader found: +" & x)
|
||||
internalError(info, "rrGetSym: no reader found: +" & x)
|
||||
else:
|
||||
# own symbol:
|
||||
result = decodeSymSafePos(r, d, info)
|
||||
if result != nil and result.kind == skStub: rawLoadStub(result)
|
||||
|
||||
proc loadInitSection(r: PRodReader): PNode =
|
||||
if r.initIdx == 0 or r.dataIdx == 0: InternalError("loadInitSection")
|
||||
if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection")
|
||||
var oldPos = r.pos
|
||||
r.pos = r.initIdx
|
||||
result = newNode(nkStmtList)
|
||||
@@ -771,7 +775,7 @@ proc loadInitSection(r: PRodReader): PNode =
|
||||
inc(r.pos) # #10
|
||||
var p = r.pos
|
||||
r.pos = d + r.dataIdx
|
||||
addSon(result, decodeNode(r, UnknownLineInfo()))
|
||||
addSon(result, decodeNode(r, unknownLineInfo()))
|
||||
r.pos = p
|
||||
r.pos = oldPos
|
||||
|
||||
@@ -779,24 +783,24 @@ proc loadConverters(r: PRodReader) =
|
||||
# We have to ensure that no exported converter is a stub anymore, and the
|
||||
# import mechanism takes care of the rest.
|
||||
if r.convertersIdx == 0 or r.dataIdx == 0:
|
||||
InternalError("importConverters")
|
||||
internalError("importConverters")
|
||||
r.pos = r.convertersIdx
|
||||
while r.s[r.pos] > '\x0A':
|
||||
var d = decodeVInt(r.s, r.pos)
|
||||
discard rrGetSym(r, d, UnknownLineInfo())
|
||||
discard rrGetSym(r, d, unknownLineInfo())
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
|
||||
proc loadMethods(r: PRodReader) =
|
||||
if r.methodsIdx == 0 or r.dataIdx == 0:
|
||||
InternalError("loadMethods")
|
||||
internalError("loadMethods")
|
||||
r.pos = r.methodsIdx
|
||||
while r.s[r.pos] > '\x0A':
|
||||
var d = decodeVInt(r.s, r.pos)
|
||||
r.methods.add(rrGetSym(r, d, UnknownLineInfo()))
|
||||
r.methods.add(rrGetSym(r, d, unknownLineInfo()))
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
|
||||
proc GetCRC*(fileIdx: int32): TCrc32 =
|
||||
InternalAssert fileIdx >= 0 and fileIdx < gMods.len
|
||||
proc getCRC*(fileIdx: int32): TCrc32 =
|
||||
internalAssert fileIdx >= 0 and fileIdx < gMods.len
|
||||
|
||||
if gMods[fileIdx].crcDone:
|
||||
return gMods[fileIdx].crc
|
||||
@@ -814,14 +818,14 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
|
||||
# reason has already been computed for this module:
|
||||
return gMods[fileIdx].reason
|
||||
let filename = fileIdx.toFilename
|
||||
var crc = GetCRC(fileIdx)
|
||||
var crc = getCRC(fileIdx)
|
||||
gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles
|
||||
result = rrNone
|
||||
var r: PRodReader = nil
|
||||
var rodfile = toGeneratedFile(filename, RodExt)
|
||||
var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
|
||||
r = newRodReader(rodfile, crc, fileIdx)
|
||||
if r == nil:
|
||||
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
|
||||
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
|
||||
else:
|
||||
processRodFile(r, crc)
|
||||
result = r.reason
|
||||
@@ -830,7 +834,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
|
||||
# NOTE: we need to process the entire module graph so that no ID will
|
||||
# be used twice! However, compilation speed does not suffer much from
|
||||
# this, since results are cached.
|
||||
var res = checkDep(SystemFileIdx)
|
||||
var res = checkDep(systemFileIdx)
|
||||
if res != rrNone: result = rrModDeps
|
||||
for i in countup(0, high(r.modDeps)):
|
||||
res = checkDep(r.modDeps[i])
|
||||
@@ -841,7 +845,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
|
||||
rawMessage(hintProcessing, reasonToFrmt[result] % filename)
|
||||
if result != rrNone or optForceFullMake in gGlobalOptions:
|
||||
# recompilation is necessary:
|
||||
if r != nil: memfiles.close(r.memFile)
|
||||
if r != nil: memfiles.close(r.memfile)
|
||||
r = nil
|
||||
gMods[fileIdx].rd = r
|
||||
gMods[fileIdx].reason = result # now we know better
|
||||
@@ -854,11 +858,11 @@ proc handleSymbolFile(module: PSym): PRodReader =
|
||||
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
|
||||
|
||||
discard checkDep(fileIdx)
|
||||
if gMods[fileIdx].reason == rrEmpty: InternalError("handleSymbolFile")
|
||||
if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
|
||||
result = gMods[fileIdx].rd
|
||||
if result != nil:
|
||||
module.id = result.moduleID
|
||||
IdTablePut(result.syms, module, module)
|
||||
idTablePut(result.syms, module, module)
|
||||
processInterf(result, module)
|
||||
processCompilerProcs(result, module)
|
||||
loadConverters(result)
|
||||
@@ -867,26 +871,26 @@ proc handleSymbolFile(module: PSym): PRodReader =
|
||||
module.id = getID()
|
||||
|
||||
proc rawLoadStub(s: PSym) =
|
||||
if s.kind != skStub: InternalError("loadStub")
|
||||
if s.kind != skStub: internalError("loadStub")
|
||||
var rd = gMods[s.position].rd
|
||||
var theId = s.id # used for later check
|
||||
var d = IITableGet(rd.index.tab, s.id)
|
||||
if d == invalidKey: InternalError("loadStub: invalid key")
|
||||
var rs = decodeSymSafePos(rd, d, UnknownLineInfo())
|
||||
var d = iiTableGet(rd.index.tab, s.id)
|
||||
if d == InvalidKey: internalError("loadStub: invalid key")
|
||||
var rs = decodeSymSafePos(rd, d, unknownLineInfo())
|
||||
if rs != s:
|
||||
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
|
||||
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
|
||||
InternalError(rs.info, "loadStub: wrong symbol")
|
||||
internalError(rs.info, "loadStub: wrong symbol")
|
||||
elif rs.id != theId:
|
||||
InternalError(rs.info, "loadStub: wrong ID")
|
||||
internalError(rs.info, "loadStub: wrong ID")
|
||||
#MessageOut('loaded stub: ' + s.name.s);
|
||||
|
||||
proc LoadStub*(s: PSym) =
|
||||
proc loadStub*(s: PSym) =
|
||||
## loads the stub symbol `s`.
|
||||
|
||||
# deactivate the GC here because we do a deep recursion and generate no
|
||||
# garbage when restoring parts of the object graph anyway.
|
||||
# Since we die with internal errors if this fails, so no try-finally is
|
||||
# Since we die with internal errors if this fails, no try-finally is
|
||||
# necessary.
|
||||
GC_disable()
|
||||
rawLoadStub(s)
|
||||
@@ -908,8 +912,8 @@ proc getBody*(s: PSym): PNode =
|
||||
s.ast.sons[bodyPos] = result
|
||||
s.offset = 0
|
||||
|
||||
InitIdTable(gTypeTable)
|
||||
InitStrTable(rodCompilerProcs)
|
||||
initIdTable(gTypeTable)
|
||||
initStrTable(rodCompilerprocs)
|
||||
|
||||
# viewer:
|
||||
proc writeNode(f: TFile; n: PNode) =
|
||||
@@ -1034,8 +1038,12 @@ proc viewFile(rodfile: string) =
|
||||
of "ID":
|
||||
inc(r.pos) # skip ':'
|
||||
r.moduleID = decodeVInt(r.s, r.pos)
|
||||
setID(r.moduleID)
|
||||
setId(r.moduleID)
|
||||
outf.writeln("ID:", $r.moduleID)
|
||||
of "ORIGFILE":
|
||||
inc(r.pos)
|
||||
r.origFile = decodeStr(r.s, r.pos)
|
||||
outf.writeln("ORIGFILE:", r.origFile)
|
||||
of "OPTIONS":
|
||||
inc(r.pos) # skip ':'
|
||||
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
|
||||
@@ -1058,13 +1066,13 @@ proc viewFile(rodfile: string) =
|
||||
outf.write(" ", w)
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
outf.write("\n")
|
||||
of "FILES":
|
||||
of "FILES":
|
||||
inc(r.pos, 2) # skip "(\10"
|
||||
inc(r.line)
|
||||
outf.write("FILES(\n")
|
||||
while r.s[r.pos] != ')':
|
||||
let relativePath = decodeStr(r.s, r.pos)
|
||||
let resolvedPath = relativePath.findModule
|
||||
let resolvedPath = relativePath.findModule(r.origFile)
|
||||
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
|
||||
r.files.add(finalPath.fileInfoIdx)
|
||||
inc(r.pos) # skip #10
|
||||
@@ -1132,12 +1140,12 @@ proc viewFile(rodfile: string) =
|
||||
outf.write("DATA(\n")
|
||||
while r.s[r.pos] != ')':
|
||||
if r.s[r.pos] == '(':
|
||||
outf.writeNode decodeNode(r, UnknownLineInfo())
|
||||
outf.writeNode decodeNode(r, unknownLineInfo())
|
||||
outf.write("\n")
|
||||
elif r.s[r.pos] == '[':
|
||||
outf.writeType decodeType(r, UnknownLineInfo())
|
||||
outf.writeType decodeType(r, unknownLineInfo())
|
||||
else:
|
||||
outf.writeSym decodeSym(r, UnknownLineInfo())
|
||||
outf.writeSym decodeSym(r, unknownLineInfo())
|
||||
if r.s[r.pos] == '\x0A':
|
||||
inc(r.pos)
|
||||
inc(r.line)
|
||||
@@ -1158,7 +1166,7 @@ proc viewFile(rodfile: string) =
|
||||
if r.s[r.pos] == ')': inc r.pos
|
||||
outf.write("<not supported by viewer>)\n")
|
||||
else:
|
||||
InternalError("invalid section: '" & section &
|
||||
internalError("invalid section: '" & section &
|
||||
"' at " & $r.line & " in " & r.filename)
|
||||
skipSection(r)
|
||||
if r.s[r.pos] == '\x0A':
|
||||
|
||||
@@ -12,7 +12,7 @@ import strutils
|
||||
|
||||
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", nodecl, varargs.}
|
||||
|
||||
proc ToStrMaxPrecision*(f: BiggestFloat): string =
|
||||
proc toStrMaxPrecision*(f: BiggestFloat): string =
|
||||
if f != f:
|
||||
result = "NAN"
|
||||
elif f == 0.0:
|
||||
@@ -36,7 +36,7 @@ proc hexChar(c: char, xi: var int) =
|
||||
of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
|
||||
of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
|
||||
of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
proc decodeStr*(s: cstring, pos: var int): string =
|
||||
var i = pos
|
||||
@@ -119,7 +119,7 @@ template decodeIntImpl() =
|
||||
proc decodeVInt*(s: cstring, pos: var int): int =
|
||||
decodeIntImpl()
|
||||
|
||||
proc decodeVBiggestInt*(s: cstring, pos: var int): biggestInt =
|
||||
proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
|
||||
decodeIntImpl()
|
||||
|
||||
iterator decodeVIntArray*(s: cstring): int =
|
||||
|
||||
@@ -34,6 +34,7 @@ type
|
||||
sstack: TSymSeq # a stack of symbols to process
|
||||
tstack: TTypeSeq # a stack of types to process
|
||||
files: TStringSeq
|
||||
origFile: string
|
||||
|
||||
PRodWriter = ref TRodWriter
|
||||
|
||||
@@ -45,21 +46,17 @@ proc addStmt(w: PRodWriter, n: PNode)
|
||||
proc writeRod(w: PRodWriter)
|
||||
|
||||
proc getDefines(): string =
|
||||
var it: TTabIter
|
||||
var s = InitTabIter(it, gSymbols)
|
||||
result = ""
|
||||
while s != nil:
|
||||
if s.position == 1:
|
||||
if result.len != 0: add(result, " ")
|
||||
add(result, s.name.s)
|
||||
s = nextIter(it, gSymbols)
|
||||
for d in definedSymbolNames():
|
||||
if result.len != 0: add(result, " ")
|
||||
add(result, d)
|
||||
|
||||
proc fileIdx(w: PRodWriter, filename: string): int =
|
||||
for i in countup(0, high(w.files)):
|
||||
if w.files[i] == filename:
|
||||
return i
|
||||
result = len(w.files)
|
||||
setlen(w.files, result + 1)
|
||||
setLen(w.files, result + 1)
|
||||
w.files[result] = filename
|
||||
|
||||
template filename*(w: PRodWriter): string =
|
||||
@@ -69,8 +66,8 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
|
||||
new(result)
|
||||
result.sstack = @[]
|
||||
result.tstack = @[]
|
||||
InitIITable(result.index.tab)
|
||||
InitIITable(result.imports.tab)
|
||||
initIiTable(result.index.tab)
|
||||
initIiTable(result.imports.tab)
|
||||
result.index.r = ""
|
||||
result.imports.r = ""
|
||||
result.crc = crc
|
||||
@@ -85,6 +82,7 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
|
||||
result.converters = ""
|
||||
result.methods = ""
|
||||
result.init = ""
|
||||
result.origFile = module.info.toFilename
|
||||
result.data = newStringOfCap(12_000)
|
||||
|
||||
proc addModDep(w: PRodWriter, dep: string) =
|
||||
@@ -95,7 +93,7 @@ const
|
||||
rodNL = "\x0A"
|
||||
|
||||
proc addInclDep(w: PRodWriter, dep: string) =
|
||||
var resolved = dep.findModule
|
||||
var resolved = dep.findModule(w.module.info.toFullPath)
|
||||
encodeVInt(fileIdx(w, dep), w.inclDeps)
|
||||
add(w.inclDeps, " ")
|
||||
encodeVInt(crcFromFile(resolved), w.inclDeps)
|
||||
@@ -103,12 +101,12 @@ proc addInclDep(w: PRodWriter, dep: string) =
|
||||
|
||||
proc pushType(w: PRodWriter, t: PType) =
|
||||
# check so that the stack does not grow too large:
|
||||
if IiTableGet(w.index.tab, t.id) == invalidKey:
|
||||
if iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
w.tstack.add(t)
|
||||
|
||||
proc pushSym(w: PRodWriter, s: PSym) =
|
||||
# check so that the stack does not grow too large:
|
||||
if IiTableGet(w.index.tab, s.id) == invalidKey:
|
||||
if iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
w.sstack.add(s)
|
||||
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
@@ -122,19 +120,19 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
# we do not write comments for now
|
||||
# Line information takes easily 20% or more of the filesize! Therefore we
|
||||
# omit line information if it is the same as the father's line information:
|
||||
if finfo.fileIndex != n.info.fileIndex:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
encodeVInt(n.info.line, result)
|
||||
result.add(',')
|
||||
encodeVInt(fileIdx(w, toFilename(n.info)), result)
|
||||
elif finfo.line != n.info.line:
|
||||
elif fInfo.line != n.info.line:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
encodeVInt(n.info.line, result)
|
||||
elif finfo.col != n.info.col:
|
||||
elif fInfo.col != n.info.col:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
# No need to output the file index, as this is the serialization of one
|
||||
@@ -192,7 +190,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
if loc.a != 0:
|
||||
add(result, '?')
|
||||
encodeVInt(loc.a, result)
|
||||
if oldlen + 1 == result.len:
|
||||
if oldLen + 1 == result.len:
|
||||
# no data was necessary, so remove the '<' again:
|
||||
setLen(result, oldLen)
|
||||
else:
|
||||
@@ -204,7 +202,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
result.add("[]")
|
||||
return
|
||||
# we need no surrounding [] here because the type is in a line of its own
|
||||
if t.kind == tyForward: InternalError("encodeType: tyForward")
|
||||
if t.kind == tyForward: internalError("encodeType: tyForward")
|
||||
# for the new rodfile viewer we use a preceeding [ so that the data section
|
||||
# can easily be disambiguated:
|
||||
add(result, '[')
|
||||
@@ -212,7 +210,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
add(result, '+')
|
||||
encodeVInt(t.id, result)
|
||||
if t.n != nil:
|
||||
encodeNode(w, UnknownLineInfo(), t.n, result)
|
||||
encodeNode(w, unknownLineInfo(), t.n, result)
|
||||
if t.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](t.flags), result)
|
||||
@@ -294,7 +292,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||
if s.constraint != nil:
|
||||
add(result, '#')
|
||||
encodeNode(w, UnknownLineInfo(), s.constraint, result)
|
||||
encodeNode(w, unknownLineInfo(), s.constraint, result)
|
||||
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
@@ -324,7 +322,7 @@ proc addToIndex(w: var TIndex, key, val: int) =
|
||||
add(w.r, rodNL)
|
||||
w.lastIdxKey = key
|
||||
w.lastIdxVal = val
|
||||
IiTablePut(w.tab, key, val)
|
||||
iiTablePut(w.tab, key, val)
|
||||
|
||||
const debugWrittenIds = false
|
||||
|
||||
@@ -338,9 +336,9 @@ proc symStack(w: PRodWriter): int =
|
||||
if sfForward in s.flags:
|
||||
w.sstack[result] = s
|
||||
inc result
|
||||
elif IiTableGet(w.index.tab, s.id) == invalidKey:
|
||||
elif iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
var m = getModule(s)
|
||||
if m == nil: InternalError("symStack: module nil: " & s.name.s)
|
||||
if m == nil: internalError("symStack: module nil: " & s.name.s)
|
||||
if (m.id == w.module.id) or (sfFromGeneric in s.flags):
|
||||
# put definition in here
|
||||
var L = w.data.len
|
||||
@@ -366,7 +364,7 @@ proc symStack(w: PRodWriter): int =
|
||||
if s.kind == skMethod and sfDispatcher notin s.flags:
|
||||
if w.methods.len != 0: add(w.methods, ' ')
|
||||
encodeVInt(s.id, w.methods)
|
||||
elif IiTableGet(w.imports.tab, s.id) == invalidKey:
|
||||
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
|
||||
addToIndex(w.imports, s.id, m.id)
|
||||
when debugWrittenIds:
|
||||
if not Contains(debugWritten, s.id):
|
||||
@@ -376,7 +374,7 @@ proc symStack(w: PRodWriter): int =
|
||||
debug(m)
|
||||
InternalError("Symbol referred to but never written")
|
||||
inc(i)
|
||||
setlen(w.sstack, result)
|
||||
setLen(w.sstack, result)
|
||||
|
||||
proc typeStack(w: PRodWriter): int =
|
||||
var i = 0
|
||||
@@ -385,13 +383,13 @@ proc typeStack(w: PRodWriter): int =
|
||||
if t.kind == tyForward:
|
||||
w.tstack[result] = t
|
||||
inc result
|
||||
elif IiTableGet(w.index.tab, t.id) == invalidKey:
|
||||
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
var L = w.data.len
|
||||
addToIndex(w.index, t.id, L)
|
||||
encodeType(w, t, w.data)
|
||||
add(w.data, rodNL)
|
||||
inc(i)
|
||||
setlen(w.tstack, result)
|
||||
setLen(w.tstack, result)
|
||||
|
||||
proc processStacks(w: PRodWriter, finalPass: bool) =
|
||||
var oldS = 0
|
||||
@@ -403,7 +401,7 @@ proc processStacks(w: PRodWriter, finalPass: bool) =
|
||||
oldS = slen
|
||||
oldT = tlen
|
||||
if finalPass and (oldS != 0 or oldT != 0):
|
||||
InternalError("could not serialize some forwarded symbols/types")
|
||||
internalError("could not serialize some forwarded symbols/types")
|
||||
|
||||
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
pushSym(w, s)
|
||||
@@ -418,14 +416,15 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
proc addStmt(w: PRodWriter, n: PNode) =
|
||||
encodeVInt(w.data.len, w.init)
|
||||
add(w.init, rodNL)
|
||||
encodeNode(w, UnknownLineInfo(), n, w.data)
|
||||
encodeNode(w, unknownLineInfo(), n, w.data)
|
||||
add(w.data, rodNL)
|
||||
processStacks(w, false)
|
||||
|
||||
proc writeRod(w: PRodWriter) =
|
||||
processStacks(w, true)
|
||||
var f: TFile
|
||||
if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")),
|
||||
if not open(f, completeGeneratedFilePath(changeFileExt(
|
||||
w.filename.withPackageName, RodExt)),
|
||||
fmWrite):
|
||||
#echo "couldn't write rod file for: ", w.filename
|
||||
return
|
||||
@@ -437,6 +436,11 @@ proc writeRod(w: PRodWriter) =
|
||||
encodeVInt(w.module.id, id)
|
||||
f.write(id)
|
||||
f.write(rodNL)
|
||||
|
||||
var orig = "ORIGFILE:"
|
||||
encodeStr(w.origFile, orig)
|
||||
f.write(orig)
|
||||
f.write(rodNL)
|
||||
|
||||
var crc = "CRC:"
|
||||
encodeVInt(w.crc, crc)
|
||||
@@ -530,9 +534,9 @@ proc process(c: PPassContext, n: PNode): PNode =
|
||||
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef,
|
||||
nkTemplateDef, nkMacroDef:
|
||||
var s = n.sons[namePos].sym
|
||||
if s == nil: InternalError(n.info, "rodwrite.process")
|
||||
if s == nil: internalError(n.info, "rodwrite.process")
|
||||
if n.sons[bodyPos] == nil:
|
||||
InternalError(n.info, "rodwrite.process: body is nil")
|
||||
internalError(n.info, "rodwrite.process: body is nil")
|
||||
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
|
||||
sfForward notin s.flags:
|
||||
addInterfaceSym(w, s)
|
||||
@@ -545,7 +549,7 @@ proc process(c: PPassContext, n: PNode): PNode =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process")
|
||||
if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
|
||||
var s = a.sons[0].sym
|
||||
addInterfaceSym(w, s)
|
||||
# this takes care of enum fields too
|
||||
@@ -569,11 +573,11 @@ proc process(c: PPassContext, n: PNode): PNode =
|
||||
of nkPragma:
|
||||
addStmt(w, n)
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
if module.id < 0: InternalError("rodwrite: module ID not set")
|
||||
var w = newRodWriter(module.fileIdx.GetCRC, module)
|
||||
if module.id < 0: internalError("rodwrite: module ID not set")
|
||||
var w = newRodWriter(module.fileIdx.getCRC, module)
|
||||
rawAddInterfaceSym(w, module)
|
||||
result = w
|
||||
|
||||
|
||||
@@ -91,13 +91,13 @@ proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
|
||||
proc ropeToStr*(p: PRope): string
|
||||
proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
|
||||
proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
|
||||
proc RopeEqualsFile*(r: PRope, f: string): bool
|
||||
proc ropeEqualsFile*(r: PRope, f: string): bool
|
||||
# returns true if the rope r is the same as the contents of file f
|
||||
proc RopeInvariant*(r: PRope): bool
|
||||
proc ropeInvariant*(r: PRope): bool
|
||||
# exported for debugging
|
||||
# implementation
|
||||
|
||||
var ErrorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
|
||||
var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
|
||||
# avoid dependency on msgs.nim
|
||||
|
||||
proc ropeLen(a: PRope): int =
|
||||
@@ -126,7 +126,7 @@ proc resetRopeCache* =
|
||||
for i in low(cache)..high(cache):
|
||||
cache[i] = nil
|
||||
|
||||
proc RopeInvariant(r: PRope): bool =
|
||||
proc ropeInvariant(r: PRope): bool =
|
||||
if r == nil:
|
||||
result = true
|
||||
else:
|
||||
@@ -157,14 +157,14 @@ proc toRope(s: string): PRope =
|
||||
result = nil
|
||||
else:
|
||||
result = insertInCache(s)
|
||||
assert(RopeInvariant(result))
|
||||
assert(ropeInvariant(result))
|
||||
|
||||
proc RopeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
|
||||
proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
|
||||
var length = len(rs)
|
||||
if at > length:
|
||||
setlen(rs, at + 1)
|
||||
setLen(rs, at + 1)
|
||||
else:
|
||||
setlen(rs, length + 1) # move old rope elements:
|
||||
setLen(rs, length + 1) # move old rope elements:
|
||||
for i in countdown(length, at + 1):
|
||||
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
|
||||
rs[at] = r
|
||||
@@ -177,8 +177,8 @@ proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
|
||||
add(stack, it.right)
|
||||
it = it.left
|
||||
assert(it.data != nil)
|
||||
CopyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
|
||||
Inc(resultLen, it.length)
|
||||
copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
|
||||
inc(resultLen, it.length)
|
||||
assert(resultLen <= len(result))
|
||||
|
||||
proc ropeToStr(p: PRope): string =
|
||||
@@ -227,13 +227,13 @@ proc writeRope*(f: TFile, c: PRope) =
|
||||
assert(it.data != nil)
|
||||
write(f, it.data)
|
||||
|
||||
proc WriteRope*(head: PRope, filename: string, useWarning = false) =
|
||||
var f: tfile
|
||||
proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
||||
var f: TFile
|
||||
if open(f, filename, fmWrite):
|
||||
if head != nil: WriteRope(f, head)
|
||||
if head != nil: writeRope(f, head)
|
||||
close(f)
|
||||
else:
|
||||
ErrorHandler(rCannotOpenFile, filename, useWarning)
|
||||
errorHandler(rCannotOpenFile, filename, useWarning)
|
||||
|
||||
var
|
||||
rnl* = tnl.newRope
|
||||
@@ -258,12 +258,12 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
num = j
|
||||
if j > high(args) + 1:
|
||||
ErrorHandler(rInvalidFormatStr, $(j))
|
||||
errorHandler(rInvalidFormatStr, $(j))
|
||||
else:
|
||||
app(result, args[j - 1])
|
||||
of 'n':
|
||||
@@ -273,22 +273,25 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
app(result, rnl)
|
||||
inc(i)
|
||||
else:
|
||||
ErrorHandler(rInvalidFormatStr, $(frmt[i]))
|
||||
errorHandler(rInvalidFormatStr, $(frmt[i]))
|
||||
var start = i
|
||||
while i < length:
|
||||
if frmt[i] != '$': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
app(result, substr(frmt, start, i - 1))
|
||||
assert(RopeInvariant(result))
|
||||
assert(ropeInvariant(result))
|
||||
|
||||
{.push stack_trace: off, line_trace: off.}
|
||||
proc `~`*(r: expr[string]): PRope =
|
||||
# this is the new optimized "to rope" operator
|
||||
# the mnemonic is that `~` looks a bit like a rope :)
|
||||
var r {.global.} = r.ropef
|
||||
return r
|
||||
{.pop.}
|
||||
when true:
|
||||
template `~`*(r: string): PRope = r.ropef
|
||||
else:
|
||||
{.push stack_trace: off, line_trace: off.}
|
||||
proc `~`*(r: static[string]): PRope =
|
||||
# this is the new optimized "to rope" operator
|
||||
# the mnemonic is that `~` looks a bit like a rope :)
|
||||
var r {.global.} = r.ropef
|
||||
return r
|
||||
{.pop.}
|
||||
|
||||
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
||||
app(c, ropef(frmt, args))
|
||||
@@ -296,10 +299,10 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
||||
const
|
||||
bufSize = 1024 # 1 KB is reasonable
|
||||
|
||||
proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool =
|
||||
proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
|
||||
if r.data != nil:
|
||||
if r.length > bufSize:
|
||||
ErrorHandler(rTokenTooLong, r.data)
|
||||
errorHandler(rTokenTooLong, r.data)
|
||||
return
|
||||
var readBytes = readBuffer(bin, buf, r.length)
|
||||
result = readBytes == r.length and
|
||||
@@ -308,12 +311,12 @@ proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool =
|
||||
result = auxRopeEqualsFile(r.left, bin, buf)
|
||||
if result: result = auxRopeEqualsFile(r.right, bin, buf)
|
||||
|
||||
proc RopeEqualsFile(r: PRope, f: string): bool =
|
||||
var bin: tfile
|
||||
proc ropeEqualsFile(r: PRope, f: string): bool =
|
||||
var bin: TFile
|
||||
result = open(bin, f)
|
||||
if not result:
|
||||
return # not equal if file does not exist
|
||||
var buf = alloc(BufSize)
|
||||
var buf = alloc(bufSize)
|
||||
result = auxRopeEqualsFile(r, bin, buf)
|
||||
if result:
|
||||
result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
|
||||
@@ -346,7 +349,7 @@ proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
|
||||
inc(i)
|
||||
|
||||
proc crcFromRope(r: PRope): TCrc32 =
|
||||
result = newCrcFromRopeAux(r, initCrc32)
|
||||
result = newCrcFromRopeAux(r, InitCrc32)
|
||||
|
||||
proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
|
||||
# returns true if overwritten
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## Saturated arithmetic routines. XXX Make part of the stdlib?
|
||||
|
||||
proc `|+|`*(a, b: biggestInt): biggestInt =
|
||||
proc `|+|`*(a, b: BiggestInt): BiggestInt =
|
||||
## saturated addition.
|
||||
result = a +% b
|
||||
if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
|
||||
@@ -19,7 +19,7 @@ proc `|+|`*(a, b: biggestInt): biggestInt =
|
||||
else:
|
||||
result = high(result)
|
||||
|
||||
proc `|-|`*(a, b: biggestInt): biggestInt =
|
||||
proc `|-|`*(a, b: BiggestInt): BiggestInt =
|
||||
result = a -% b
|
||||
if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
|
||||
return result
|
||||
@@ -28,14 +28,14 @@ proc `|-|`*(a, b: biggestInt): biggestInt =
|
||||
else:
|
||||
result = high(result)
|
||||
|
||||
proc `|abs|`*(a: biggestInt): biggestInt =
|
||||
proc `|abs|`*(a: BiggestInt): BiggestInt =
|
||||
if a != low(a):
|
||||
if a >= 0: result = a
|
||||
else: result = -a
|
||||
else:
|
||||
result = low(a)
|
||||
|
||||
proc `|div|`*(a, b: biggestInt): biggestInt =
|
||||
proc `|div|`*(a, b: BiggestInt): BiggestInt =
|
||||
# (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
|
||||
if b == 0'i64:
|
||||
# make the same as ``div 1``:
|
||||
@@ -45,13 +45,13 @@ proc `|div|`*(a, b: biggestInt): biggestInt =
|
||||
else:
|
||||
result = a div b
|
||||
|
||||
proc `|mod|`*(a, b: biggestInt): biggestInt =
|
||||
proc `|mod|`*(a, b: BiggestInt): BiggestInt =
|
||||
if b == 0'i64:
|
||||
result = a
|
||||
else:
|
||||
result = a mod b
|
||||
|
||||
proc `|*|`*(a, b: biggestInt): biggestInt =
|
||||
proc `|*|`*(a, b: BiggestInt): BiggestInt =
|
||||
var
|
||||
resAsFloat, floatProd: float64
|
||||
result = a *% b
|
||||
|
||||
278
compiler/sem.nim
278
compiler/sem.nim
@@ -14,8 +14,8 @@ import
|
||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||
semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2
|
||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity
|
||||
|
||||
# implementation
|
||||
|
||||
@@ -36,29 +36,40 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode
|
||||
proc fixImmediateParams(n: PNode): PNode
|
||||
proc activate(c: PContext, n: PNode)
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||
proc finishMethod(c: PContext, s: PSym)
|
||||
|
||||
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
|
||||
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
|
||||
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
typeToString(actual) & ") " &
|
||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||
|
||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
result = IndexTypesMatch(c, formal, arg.typ, arg)
|
||||
if result == nil:
|
||||
typeMismatch(arg, formal, arg.typ)
|
||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
if arg.typ.isNil:
|
||||
localError(arg.info, errExprXHasNoType,
|
||||
renderTree(arg, {renderNoComments}))
|
||||
# error correction:
|
||||
result = copyNode(arg)
|
||||
result.typ = formal
|
||||
else:
|
||||
result = indexTypesMatch(c, formal, arg.typ, arg)
|
||||
if result == nil:
|
||||
typeMismatch(arg, formal, arg.typ)
|
||||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
|
||||
var CommonTypeBegin = PType(kind: tyExpr)
|
||||
proc inferWithMetatype(c: PContext, formal: PType,
|
||||
arg: PNode, coerceDistincts = false): PNode
|
||||
|
||||
var commonTypeBegin = PType(kind: tyExpr)
|
||||
|
||||
proc commonType*(x, y: PType): PType =
|
||||
# new type relation that is used for array constructors,
|
||||
@@ -75,27 +86,48 @@ proc commonType*(x, y: PType): PType =
|
||||
elif a.kind == tyTypeDesc:
|
||||
# turn any concrete typedesc into the abstract typedesc type
|
||||
if a.sons == nil: result = a
|
||||
else: result = newType(tyTypeDesc, a.owner)
|
||||
else:
|
||||
result = newType(tyTypeDesc, a.owner)
|
||||
rawAddSon(result, newType(tyNone, a.owner))
|
||||
elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
|
||||
a.kind == b.kind:
|
||||
# check for seq[empty] vs. seq[int]
|
||||
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
||||
if a.sons[idx].kind == tyEmpty: return y
|
||||
#elif b.sons[idx].kind == tyEmpty: return x
|
||||
elif a.kind == tyRange and b.kind == tyRange:
|
||||
# consider: (range[0..3], range[0..4]) here. We should make that
|
||||
# range[0..4]. But then why is (range[0..4], 6) not range[0..6]?
|
||||
# But then why is (2,4) not range[2..4]? But I think this would break
|
||||
# too much code. So ... it's the same range or the base type. This means
|
||||
# type(if b: 0 else 1) == int and not range[0..1]. For now. In the long
|
||||
# run people expect ranges to work properly within a tuple.
|
||||
if not sameType(a, b):
|
||||
result = skipTypes(a, {tyRange}).skipIntLit
|
||||
when false:
|
||||
if a.kind != tyRange and b.kind == tyRange:
|
||||
# XXX This really needs a better solution, but a proper fix now breaks
|
||||
# code.
|
||||
result = a #.skipIntLit
|
||||
elif a.kind == tyRange and b.kind != tyRange:
|
||||
result = b #.skipIntLit
|
||||
elif a.kind in IntegralTypes and a.n != nil:
|
||||
result = a #.skipIntLit
|
||||
else:
|
||||
var k = tyNone
|
||||
if a.kind in {tyRef, tyPtr}:
|
||||
k = a.kind
|
||||
if b.kind != a.kind: return x
|
||||
a = a.sons[0]
|
||||
b = b.sons[0]
|
||||
a = a.lastSon
|
||||
b = b.lastSon
|
||||
if a.kind == tyObject and b.kind == tyObject:
|
||||
result = commonSuperclass(a, b)
|
||||
# this will trigger an error later:
|
||||
if result.isNil: return x
|
||||
if result.isNil or result == a: return x
|
||||
if result == b: return y
|
||||
if k != tyNone:
|
||||
let r = result
|
||||
result = NewType(k, r.owner)
|
||||
result = newType(k, r.owner)
|
||||
result.addSonSkipIntLit(r)
|
||||
|
||||
proc isTopLevel(c: PContext): bool {.inline.} =
|
||||
@@ -108,8 +140,12 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
# like newSymS, but considers gensym'ed symbols
|
||||
if n.kind == nkSym:
|
||||
result = n.sym
|
||||
InternalAssert sfGenSym in result.flags
|
||||
InternalAssert result.kind == kind
|
||||
internalAssert sfGenSym in result.flags
|
||||
internalAssert result.kind == kind
|
||||
# when there is a nested proc inside a template, semtmpl
|
||||
# will assign a wrong owner during the first pass over the
|
||||
# template; we must fix it here: see #909
|
||||
result.owner = getCurrOwner()
|
||||
else:
|
||||
result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
|
||||
|
||||
@@ -120,37 +156,18 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym
|
||||
proc semStmtScope(c: PContext, n: PNode): PNode
|
||||
|
||||
proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||
if not typeAllowed(typ, skConst):
|
||||
LocalError(typ.n.info, errXisNoType, typeToString(typ))
|
||||
localError(typ.n.info, errXisNoType, typeToString(typ))
|
||||
|
||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
||||
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
|
||||
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
semCheck: bool = true): PNode
|
||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
|
||||
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
|
||||
|
||||
proc evalTypedExpr(c: PContext, e: PNode): PNode =
|
||||
result = getConstExpr(c.module, e)
|
||||
if result == nil:
|
||||
result = evalConstExpr(c.module, e)
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
LocalError(e.info, errConstExprExpected)
|
||||
# error correction:
|
||||
result = e
|
||||
|
||||
proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
var e = semExprWithType(c, n)
|
||||
if e == nil:
|
||||
LocalError(n.info, errConstExprExpected)
|
||||
return n
|
||||
result = evalTypedExpr(c, e)
|
||||
|
||||
include hlo, seminst, semcall
|
||||
proc isOpImpl(c: PContext, n: PNode): PNode
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags = {}): PNode
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
flags: TExprFlags = {}): PNode
|
||||
|
||||
proc symFromType(t: PType, info: TLineInfo): PSym =
|
||||
if t.sym != nil: return t.sym
|
||||
@@ -162,10 +179,100 @@ proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
|
||||
result = newSymNode(symFromType(t, info), info)
|
||||
result.typ = makeTypeDesc(c, t)
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||
when false:
|
||||
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
|
||||
result = newEvalContext(c.module, mode)
|
||||
result.getType = proc (n: PNode): PNode =
|
||||
result = tryExpr(c, n)
|
||||
if result == nil:
|
||||
result = newSymNode(errorSym(c, n))
|
||||
elif result.typ == nil:
|
||||
result = newSymNode(getSysSym"void")
|
||||
else:
|
||||
result.typ = makeTypeDesc(c, result.typ)
|
||||
|
||||
result.handleIsOperator = proc (n: PNode): PNode =
|
||||
result = isOpImpl(c, n)
|
||||
|
||||
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
|
||||
# recompute the types as 'eval' isn't guaranteed to construct types nor
|
||||
# that the types are sound:
|
||||
when true:
|
||||
if eOrig.typ.kind in {tyExpr, tyStmt, tyTypeDesc}:
|
||||
result = semExprWithType(c, evaluated)
|
||||
else:
|
||||
result = evaluated
|
||||
let expectedType = eOrig.typ.skipTypes({tyStatic})
|
||||
semmacrosanity.annotateType(result, expectedType)
|
||||
else:
|
||||
result = semExprWithType(c, evaluated)
|
||||
#result = fitNode(c, e.typ, result) inlined with special case:
|
||||
let arg = result
|
||||
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
|
||||
if result == nil:
|
||||
result = arg
|
||||
# for 'tcnstseq' we support [] to become 'seq'
|
||||
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
|
||||
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
|
||||
arg.typ = eOrig.typ
|
||||
|
||||
proc tryConstExpr(c: PContext, n: PNode): PNode =
|
||||
var e = semExprWithType(c, n)
|
||||
if e == nil: return
|
||||
|
||||
result = getConstExpr(c.module, e)
|
||||
if result != nil: return
|
||||
|
||||
let oldErrorCount = msgs.gErrorCounter
|
||||
let oldErrorMax = msgs.gErrorMax
|
||||
let oldErrorOutputs = errorOutputs
|
||||
|
||||
errorOutputs = {}
|
||||
msgs.gErrorMax = high(int)
|
||||
|
||||
try:
|
||||
result = evalConstExpr(c.module, e)
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
result = nil
|
||||
else:
|
||||
result = fixupTypeAfterEval(c, result, e)
|
||||
|
||||
except ERecoverableError:
|
||||
result = nil
|
||||
|
||||
msgs.gErrorCounter = oldErrorCount
|
||||
msgs.gErrorMax = oldErrorMax
|
||||
errorOutputs = oldErrorOutputs
|
||||
|
||||
proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
var e = semExprWithType(c, n)
|
||||
if e == nil:
|
||||
localError(n.info, errConstExprExpected)
|
||||
return n
|
||||
result = getConstExpr(c.module, e)
|
||||
if result == nil:
|
||||
result = evalConstExpr(c.module, e)
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
if e.info != n.info:
|
||||
pushInfoContext(n.info)
|
||||
localError(e.info, errConstExprExpected)
|
||||
popInfoContext()
|
||||
else:
|
||||
localError(e.info, errConstExprExpected)
|
||||
# error correction:
|
||||
result = e
|
||||
else:
|
||||
result = fixupTypeAfterEval(c, result, e)
|
||||
|
||||
include hlo, seminst, semcall
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
inc(evalTemplateCounter)
|
||||
if evalTemplateCounter > 100:
|
||||
GlobalError(s.info, errTemplateInstantiationTooNested)
|
||||
globalError(s.info, errTemplateInstantiationTooNested)
|
||||
let oldFriend = c.friendModule
|
||||
c.friendModule = s.owner.getModule
|
||||
|
||||
result = n
|
||||
if s.typ.sons[0] == nil:
|
||||
@@ -176,38 +283,33 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||
# BUGFIX: we cannot expect a type here, because module aliases would not
|
||||
# work then (see the ``tmodulealias`` test)
|
||||
# semExprWithType(c, result)
|
||||
result = semExpr(c, result)
|
||||
result = semExpr(c, result, flags)
|
||||
of tyStmt:
|
||||
result = semStmt(c, result)
|
||||
of tyTypeDesc:
|
||||
if n.kind == nkStmtList: result.kind = nkStmtListType
|
||||
var typ = semTypeNode(c, result, nil)
|
||||
result = symNodeFromType(c, typ, n.info)
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
else:
|
||||
result = semExpr(c, result)
|
||||
result = semExpr(c, result, flags)
|
||||
result = fitNode(c, s.typ.sons[0], result)
|
||||
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
||||
dec(evalTemplateCounter)
|
||||
c.friendModule = oldFriend
|
||||
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
semCheck: bool = true): PNode =
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
markUsed(n, sym)
|
||||
if sym == c.p.owner:
|
||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||
globalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||
|
||||
if c.evalContext == nil:
|
||||
c.evalContext = newEvalContext(c.module, emStatic)
|
||||
c.evalContext.getType = proc (n: PNode): PNode =
|
||||
var e = tryExpr(c, n)
|
||||
if e == nil:
|
||||
result = symNodeFromType(c, errorType(c), n.info)
|
||||
elif e.typ == nil:
|
||||
result = newSymNode(getSysSym"void")
|
||||
else:
|
||||
result = symNodeFromType(c, e.typ, n.info)
|
||||
#if c.evalContext == nil:
|
||||
# c.evalContext = c.createEvalContext(emStatic)
|
||||
|
||||
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||
result = evalMacroCall(c.module, n, nOrig, sym)
|
||||
if efNoSemCheck notin flags:
|
||||
result = semAfterMacroCall(c, result, sym, flags)
|
||||
|
||||
proc forceBool(c: PContext, n: PNode): PNode =
|
||||
result = fitNode(c, getSysType(tyBool), n)
|
||||
@@ -217,13 +319,21 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
||||
let nn = semExprWithType(c, n)
|
||||
result = fitNode(c, getSysType(tyBool), nn)
|
||||
if result == nil:
|
||||
LocalError(n.info, errConstExprExpected)
|
||||
localError(n.info, errConstExprExpected)
|
||||
return nn
|
||||
result = getConstExpr(c.module, result)
|
||||
if result == nil:
|
||||
LocalError(n.info, errConstExprExpected)
|
||||
localError(n.info, errConstExprExpected)
|
||||
result = nn
|
||||
|
||||
type
|
||||
TSemGenericFlag = enum
|
||||
withinBind, withinTypeDesc, withinMixin
|
||||
TSemGenericFlags = set[TSemGenericFlag]
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode
|
||||
|
||||
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
||||
|
||||
proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||
@@ -231,29 +341,33 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||
var prc = c.generics[i].inst.sym
|
||||
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
|
||||
if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
|
||||
InternalError(prc.info, "no code for " & prc.name.s)
|
||||
internalError(prc.info, "no code for " & prc.name.s)
|
||||
else:
|
||||
addSon(n, prc.ast)
|
||||
c.lastGenericIdx = c.generics.len
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
var c = newContext(module)
|
||||
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
||||
if c.p != nil: internalError(module.info, "sem.myOpen")
|
||||
c.semConstExpr = semConstExpr
|
||||
c.semExpr = semExpr
|
||||
c.semTryExpr = tryExpr
|
||||
c.semTryConstExpr = tryConstExpr
|
||||
c.semOperand = semOperand
|
||||
c.semConstBoolExpr = semConstBoolExpr
|
||||
c.semOverloadedCall = semOverloadedCall
|
||||
c.semInferredLambda = semInferredLambda
|
||||
c.semGenerateInstance = generateInstance
|
||||
c.semTypeNode = semTypeNode
|
||||
pushProcCon(c, module)
|
||||
pushOwner(c.module)
|
||||
c.importTable = openScope(c)
|
||||
c.importTable.addSym(module) # a module knows itself
|
||||
if sfSystemModule in module.flags:
|
||||
magicsys.SystemModule = module # set global variable!
|
||||
magicsys.systemModule = module # set global variable!
|
||||
else:
|
||||
c.importTable.addSym magicsys.SystemModule # import the "System" identifier
|
||||
importAllSymbols(c, magicsys.SystemModule)
|
||||
c.importTable.addSym magicsys.systemModule # import the "System" identifier
|
||||
importAllSymbols(c, magicsys.systemModule)
|
||||
c.topLevelScope = openScope(c)
|
||||
result = c
|
||||
|
||||
@@ -261,7 +375,7 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||
result = myOpen(module)
|
||||
for m in items(rd.methods): methodDef(m, true)
|
||||
|
||||
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
result = semStmt(c, n)
|
||||
# BUGFIX: process newly generated generics here, not at the end!
|
||||
if c.lastGenericIdx < c.generics.len:
|
||||
@@ -276,7 +390,7 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
result = buildEchoStmt(c, result)
|
||||
result = transformStmt(c.module, result)
|
||||
|
||||
proc RecoverContext(c: PContext) =
|
||||
proc recoverContext(c: PContext) =
|
||||
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
||||
# faster than wrapping every stack operation in a 'try finally' block and
|
||||
# requires far less code.
|
||||
@@ -288,36 +402,30 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
# no need for an expensive 'try' if we stop after the first error anyway:
|
||||
if msgs.gErrorMax <= 1:
|
||||
result = SemStmtAndGenerateGenerics(c, n)
|
||||
result = semStmtAndGenerateGenerics(c, n)
|
||||
else:
|
||||
let oldContextLen = msgs.getInfoContextLen()
|
||||
let oldInGenericInst = c.InGenericInst
|
||||
let oldInGenericInst = c.inGenericInst
|
||||
try:
|
||||
result = SemStmtAndGenerateGenerics(c, n)
|
||||
result = semStmtAndGenerateGenerics(c, n)
|
||||
except ERecoverableError, ESuggestDone:
|
||||
RecoverContext(c)
|
||||
c.InGenericInst = oldInGenericInst
|
||||
recoverContext(c)
|
||||
c.inGenericInst = oldInGenericInst
|
||||
msgs.setInfoContextLen(oldContextLen)
|
||||
if getCurrentException() of ESuggestDone: result = nil
|
||||
else: result = ast.emptyNode
|
||||
#if gCmd == cmdIdeTools: findSuggest(c, n)
|
||||
|
||||
proc checkThreads(c: PContext) =
|
||||
if not needsGlobalAnalysis(): return
|
||||
for i in 0 .. c.threadEntries.len-1:
|
||||
semthreads.AnalyseThreadProc(c.threadEntries[i])
|
||||
|
||||
|
||||
proc myClose(context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
closeScope(c) # close module's scope
|
||||
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
||||
result = newNode(nkStmtList)
|
||||
if n != nil:
|
||||
InternalError(n.info, "n is not nil") #result := n;
|
||||
internalError(n.info, "n is not nil") #result := n;
|
||||
addCodeForGenerics(c, result)
|
||||
if c.module.ast != nil:
|
||||
result.add(c.module.ast)
|
||||
checkThreads(c)
|
||||
popOwner()
|
||||
popProcCon(c)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
||||
if aa.sym == bb.sym:
|
||||
result = true
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
# generics have no dispatcher yet, so we need to compare the method
|
||||
# names; however, the names are equal anyway because otherwise we
|
||||
# wouldn't even consider them to be overloaded. But even this does
|
||||
@@ -34,9 +34,76 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
||||
|
||||
proc determineType(c: PContext, s: PSym)
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
n, orig: PNode,
|
||||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
errors: var seq[string]) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
|
||||
var z: TCandidate
|
||||
|
||||
if sym == nil: return
|
||||
initCandidate(c, best, sym, initialBinding, symScope)
|
||||
initCandidate(c, alt, sym, initialBinding, symScope)
|
||||
best.state = csNoMatch
|
||||
|
||||
while sym != nil:
|
||||
if sym.kind in filter:
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
|
||||
z.calleeSym = sym
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(getProcHeader(sym))
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors[errors.len - 1].add("\n " & err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
case best.state
|
||||
of csEmpty, csNoMatch: best = z
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(best, z)
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
else: discard
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
if c.inCompilesContext > 0:
|
||||
# fail fast:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1))
|
||||
add(result, ')')
|
||||
|
||||
var candidates = ""
|
||||
for err in errors:
|
||||
add(candidates, err)
|
||||
add(candidates, "\n")
|
||||
|
||||
if candidates != "":
|
||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||
|
||||
localError(n.info, errGenerated, result)
|
||||
|
||||
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
||||
for scope in walkScopes(c.currentScope):
|
||||
if scope.usingSyms != nil:
|
||||
for s in scope.usingSyms: usedSyms.safeAdd(s)
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds): TCandidate =
|
||||
var initialBinding: PNode
|
||||
var alt: TCandidate
|
||||
var f = n.sons[0]
|
||||
if f.kind == nkBracketExpr:
|
||||
# fill in the bindings:
|
||||
@@ -44,51 +111,89 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
f = f.sons[0]
|
||||
else:
|
||||
initialBinding = nil
|
||||
|
||||
var
|
||||
o: TOverloadIter
|
||||
alt, z: TCandidate
|
||||
|
||||
template best: expr = result
|
||||
#Message(n.info, warnUser, renderTree(n))
|
||||
var sym = initOverloadIter(o, c, f)
|
||||
var symScope = o.lastOverloadScope
|
||||
|
||||
if sym == nil: return
|
||||
initCandidate(best, sym, initialBinding, symScope)
|
||||
initCandidate(alt, sym, initialBinding, symScope)
|
||||
var errors: seq[string]
|
||||
var usedSyms: seq[PNode]
|
||||
|
||||
while sym != nil:
|
||||
if sym.kind in filter:
|
||||
determineType(c, sym)
|
||||
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
|
||||
z.calleeSym = sym
|
||||
matches(c, n, orig, z)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind == skIterator: inc(z.exactMatches, 200)
|
||||
case best.state
|
||||
of csEmpty, csNoMatch: best = z
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(best, z)
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
else: nil
|
||||
sym = nextOverloadIter(o, c, f)
|
||||
template pickBest(headSymbol: expr) =
|
||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||
filter, result, alt, errors)
|
||||
|
||||
if best.state == csEmpty:
|
||||
# no overloaded proc found
|
||||
# do not generate an error yet; the semantic checking will check for
|
||||
# an overloaded () operator
|
||||
elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
|
||||
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
|
||||
if best.state != csMatch:
|
||||
InternalError(n.info, "x.state is not csMatch")
|
||||
#writeMatches(best)
|
||||
gatherUsedSyms(c, usedSyms)
|
||||
if usedSyms != nil:
|
||||
var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
|
||||
else: usedSyms[0]
|
||||
|
||||
n.sons.insert(hiddenArg, 1)
|
||||
orig.sons.insert(hiddenArg, 1)
|
||||
|
||||
pickBest(f)
|
||||
|
||||
if result.state != csMatch:
|
||||
n.sons.delete(1)
|
||||
orig.sons.delete(1)
|
||||
else: return
|
||||
|
||||
pickBest(f)
|
||||
|
||||
let overloadsState = result.state
|
||||
if overloadsState != csMatch:
|
||||
if nfDotField in n.flags:
|
||||
internalAssert f.kind == nkIdent and n.sonsLen >= 2
|
||||
let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)
|
||||
|
||||
# leave the op head symbol empty,
|
||||
# we are going to try multiple variants
|
||||
n.sons[0..1] = [nil, n[1], calleeName]
|
||||
orig.sons[0..1] = [nil, orig[1], calleeName]
|
||||
|
||||
template tryOp(x) =
|
||||
let op = newIdentNode(getIdent(x), n.info)
|
||||
n.sons[0] = op
|
||||
orig.sons[0] = op
|
||||
pickBest(op)
|
||||
|
||||
if nfExplicitCall in n.flags:
|
||||
tryOp ".()"
|
||||
|
||||
if result.state in {csEmpty, csNoMatch}:
|
||||
tryOp "."
|
||||
|
||||
elif nfDotSetter in n.flags:
|
||||
internalAssert f.kind == nkIdent and n.sonsLen == 3
|
||||
let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info)
|
||||
let callOp = newIdentNode(getIdent".=", n.info)
|
||||
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||
pickBest(callOp)
|
||||
|
||||
if overloadsState == csEmpty and result.state == csEmpty:
|
||||
localError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
|
||||
return
|
||||
elif result.state != csMatch:
|
||||
if nfExprCall in n.flags:
|
||||
localError(n.info, errExprXCannotBeCalled,
|
||||
renderTree(n, {renderNoComments}))
|
||||
else:
|
||||
if {nfDotField, nfDotSetter} * n.flags != {}:
|
||||
# clean up the inserted ops
|
||||
n.sons.delete(2)
|
||||
n.sons[0] = f
|
||||
|
||||
errors = @[]
|
||||
pickBest(f)
|
||||
notFoundError(c, n, errors)
|
||||
|
||||
return
|
||||
|
||||
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
|
||||
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
|
||||
internalAssert result.state == csMatch
|
||||
#writeMatches(result)
|
||||
#writeMatches(alt)
|
||||
if c.inCompilesContext > 0:
|
||||
# quick error message for performance of 'compiles' built-in:
|
||||
GlobalError(n.Info, errGenerated, "ambiguous call")
|
||||
globalError(n.info, errGenerated, "ambiguous call")
|
||||
elif gErrorCounter == 0:
|
||||
# don't cascade errors
|
||||
var args = "("
|
||||
@@ -97,8 +202,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
add(args, typeToString(n.sons[i].typ))
|
||||
add(args, ")")
|
||||
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||
localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
|
||||
args])
|
||||
|
||||
|
||||
@@ -116,19 +221,32 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
|
||||
for i in 1 .. <n.len:
|
||||
instGenericConvertersArg(c, n.sons[i], x)
|
||||
|
||||
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, a, arg, nil)
|
||||
initCandidate(c, m, f)
|
||||
result = paramTypesMatch(m, f, a, arg, nil)
|
||||
if m.genericConverter and result != nil:
|
||||
instGenericConvertersArg(c, result, m)
|
||||
|
||||
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
|
||||
proc inferWithMetatype(c: PContext, formal: PType,
|
||||
arg: PNode, coerceDistincts = false): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(m, f)
|
||||
result = paramTypesMatch(c, m, f, n.typ, n, nil)
|
||||
initCandidate(c, m, formal)
|
||||
m.coerceDistincts = coerceDistincts
|
||||
result = paramTypesMatch(m, formal, arg.typ, arg, nil)
|
||||
if m.genericConverter and result != nil:
|
||||
instGenericConvertersArg(c, result, m)
|
||||
if result != nil:
|
||||
# This almost exactly replicates the steps taken by the compiler during
|
||||
# param matching. It performs an embarassing ammount of back-and-forth
|
||||
# type jugling, but it's the price to pay for consistency and correctness
|
||||
result.typ = generateTypeInstance(c, m.bindings, arg.info,
|
||||
formal.skipTypes({tyCompositeTypeClass}))
|
||||
else:
|
||||
typeMismatch(arg, formal, arg.typ)
|
||||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
|
||||
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
assert x.state == csMatch
|
||||
@@ -144,7 +262,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
result = x.call
|
||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||
result.typ = finalCallee.typ.sons[0]
|
||||
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
||||
if containsGenericType(result.typ): result.typ = errorType(c)
|
||||
return
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
@@ -155,15 +273,16 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds): PNode =
|
||||
var r = resolveOverloads(c, n, nOrig, filter)
|
||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||
# else: result = errorNode(c, n)
|
||||
|
||||
proc explicitGenericInstError(n: PNode): PNode =
|
||||
LocalError(n.info, errCannotInstantiateX, renderTree(n))
|
||||
localError(n.info, errCannotInstantiateX, renderTree(n))
|
||||
result = n
|
||||
|
||||
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
var x: TCandidate
|
||||
initCandidate(x, s, n)
|
||||
var newInst = generateInstance(c, s, x.bindings, n.info)
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, s, n)
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
markUsed(n, s)
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
||||
@@ -178,7 +297,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
# number of generic type parameters:
|
||||
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
|
||||
let expected = safeLen(s.ast.sons[genericParamsPos])
|
||||
LocalError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
|
||||
localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
|
||||
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
|
||||
return n
|
||||
result = explicitGenericSym(c, n, s)
|
||||
@@ -189,8 +308,9 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
result = newNodeI(a.kind, n.info)
|
||||
for i in countup(0, len(a)-1):
|
||||
var candidate = a.sons[i].sym
|
||||
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
# if suffices that the candidate has the proper number of generic
|
||||
if candidate.kind in {skProc, skMethod, skConverter,
|
||||
skIterator, skClosureIterator}:
|
||||
# it suffices that the candidate has the proper number of generic
|
||||
# type parameters:
|
||||
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
||||
result.add(explicitGenericSym(c, n, candidate))
|
||||
@@ -201,17 +321,20 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
else:
|
||||
result = explicitGenericInstError(n)
|
||||
|
||||
proc SearchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searchs for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
# New approach: generate fn(x, y, z) where x, y, z have the proper types
|
||||
# and use the overloading resolution mechanism:
|
||||
var call = newNode(nkCall)
|
||||
var call = newNodeI(nkCall, fn.info)
|
||||
var hasDistinct = false
|
||||
call.add(newIdentNode(fn.name, fn.info))
|
||||
for i in 1.. <fn.typ.n.len:
|
||||
let param = fn.typ.n.sons[i]
|
||||
let t = skipTypes(param.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
|
||||
call.add(newNodeIT(nkEmpty, fn.info, t.baseOfDistinct))
|
||||
var resolved = semOverloadedCall(c, call, call, {fn.kind})
|
||||
if resolved != nil:
|
||||
result = resolved.sons[0].sym
|
||||
if hasDistinct:
|
||||
var resolved = semOverloadedCall(c, call, call, {fn.kind})
|
||||
if resolved != nil:
|
||||
result = resolved.sons[0].sym
|
||||
|
||||
@@ -13,7 +13,7 @@ import
|
||||
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
||||
wordrecg,
|
||||
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
||||
magicsys, nversion, nimsets, parser, times, passes, rodread, evals
|
||||
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
|
||||
|
||||
type
|
||||
TOptionEntry* = object of lists.TListEntry # entries to put on a
|
||||
@@ -21,7 +21,7 @@ type
|
||||
options*: TOptions
|
||||
defaultCC*: TCallingConvention
|
||||
dynlib*: PLib
|
||||
Notes*: TNoteKinds
|
||||
notes*: TNoteKinds
|
||||
otherPragmas*: PNode # every pragma can be pushed
|
||||
|
||||
POptionEntry* = ref TOptionEntry
|
||||
@@ -32,7 +32,7 @@ type
|
||||
resultSym*: PSym # the result symbol (if we are in a proc)
|
||||
nestedLoopCounter*: int # whether we are in a loop or not
|
||||
nestedBlockCounter*: int # whether we are in a block or not
|
||||
InTryStmt*: int # whether we are in a try statement; works also
|
||||
inTryStmt*: int # whether we are in a try statement; works also
|
||||
# in standalone ``except`` and ``finally``
|
||||
next*: PProcCon # used for stacking procedure contexts
|
||||
|
||||
@@ -42,7 +42,7 @@ type
|
||||
|
||||
TExprFlag* = enum
|
||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
|
||||
efAllowDestructor
|
||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
PContext* = ref TContext
|
||||
@@ -55,15 +55,15 @@ type
|
||||
friendModule*: PSym # current friend module; may access private data;
|
||||
# this is used so that generic instantiations
|
||||
# can access private object fields
|
||||
InstCounter*: int # to prevent endless instantiations
|
||||
instCounter*: int # to prevent endless instantiations
|
||||
|
||||
threadEntries*: TSymSeq # list of thread entries to check
|
||||
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
||||
ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
||||
# store this info in the syms themselves!)
|
||||
InGenericContext*: int # > 0 if we are in a generic type
|
||||
InUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
|
||||
InGenericInst*: int # > 0 if we are instantiating a generic
|
||||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
||||
inGenericContext*: int # > 0 if we are in a generic type
|
||||
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||
inCompilesContext*: int # > 0 if we are in a ``compiles`` magic
|
||||
inGenericInst*: int # > 0 if we are instantiating a generic
|
||||
converters*: TSymSeq # sequence of converters
|
||||
patterns*: TSymSeq # sequence of pattern matchers
|
||||
optionStack*: TLinkedList
|
||||
@@ -72,18 +72,25 @@ type
|
||||
libs*: TLinkedList # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
|
||||
bufferErrors = false): PNode {.nimcall.}
|
||||
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
|
||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds): PNode {.nimcall.}
|
||||
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
|
||||
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
|
||||
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym
|
||||
includedFiles*: TIntSet # used to detect recursive include files
|
||||
userPragmas*: TStrTable
|
||||
evalContext*: PEvalContext
|
||||
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
||||
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
||||
# naming it multiple times
|
||||
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
|
||||
lastGenericIdx*: int # used for the generics stack
|
||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||
|
||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||
result.genericSym = s
|
||||
@@ -110,8 +117,8 @@ proc scopeDepth*(c: PContext): int {.inline.} =
|
||||
|
||||
# owner handling:
|
||||
proc getCurrOwner*(): PSym
|
||||
proc PushOwner*(owner: PSym)
|
||||
proc PopOwner*()
|
||||
proc pushOwner*(owner: PSym)
|
||||
proc popOwner*()
|
||||
# implementation
|
||||
|
||||
var gOwners*: seq[PSym] = @[]
|
||||
@@ -124,20 +131,20 @@ proc getCurrOwner(): PSym =
|
||||
# BUGFIX: global array is needed!
|
||||
result = gOwners[high(gOwners)]
|
||||
|
||||
proc PushOwner(owner: PSym) =
|
||||
proc pushOwner(owner: PSym) =
|
||||
add(gOwners, owner)
|
||||
|
||||
proc PopOwner() =
|
||||
proc popOwner() =
|
||||
var length = len(gOwners)
|
||||
if length > 0: setlen(gOwners, length - 1)
|
||||
else: InternalError("popOwner")
|
||||
if length > 0: setLen(gOwners, length - 1)
|
||||
else: internalError("popOwner")
|
||||
|
||||
proc lastOptionEntry(c: PContext): POptionEntry =
|
||||
result = POptionEntry(c.optionStack.tail)
|
||||
|
||||
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
|
||||
if owner == nil:
|
||||
InternalError("owner is nil")
|
||||
internalError("owner is nil")
|
||||
return
|
||||
var x: PProcCon
|
||||
new(x)
|
||||
@@ -156,25 +163,24 @@ proc newOptionEntry(): POptionEntry =
|
||||
|
||||
proc newContext(module: PSym): PContext =
|
||||
new(result)
|
||||
result.AmbiguousSymbols = initIntset()
|
||||
result.ambiguousSymbols = initIntSet()
|
||||
initLinkedList(result.optionStack)
|
||||
initLinkedList(result.libs)
|
||||
append(result.optionStack, newOptionEntry())
|
||||
result.module = module
|
||||
result.friendModule = module
|
||||
result.threadEntries = @[]
|
||||
result.converters = @[]
|
||||
result.patterns = @[]
|
||||
result.includedFiles = initIntSet()
|
||||
initStrTable(result.userPragmas)
|
||||
result.generics = @[]
|
||||
result.UnknownIdents = initIntSet()
|
||||
result.unknownIdents = initIntSet()
|
||||
|
||||
proc inclSym(sq: var TSymSeq, s: PSym) =
|
||||
var L = len(sq)
|
||||
for i in countup(0, L - 1):
|
||||
if sq[i].id == s.id: return
|
||||
setlen(sq, L + 1)
|
||||
setLen(sq, L + 1)
|
||||
sq[L] = s
|
||||
|
||||
proc addConverter*(c: PContext, conv: PSym) =
|
||||
@@ -187,24 +193,84 @@ proc newLib(kind: TLibKind): PLib =
|
||||
new(result)
|
||||
result.kind = kind #initObjectSet(result.syms)
|
||||
|
||||
proc addToLib(lib: PLib, sym: PSym) =
|
||||
#ObjectSetIncl(lib.syms, sym);
|
||||
if sym.annex != nil: LocalError(sym.info, errInvalidPragma)
|
||||
proc addToLib(lib: PLib, sym: PSym) =
|
||||
#if sym.annex != nil and not isGenericRoutine(sym):
|
||||
# LocalError(sym.info, errInvalidPragma)
|
||||
sym.annex = lib
|
||||
|
||||
proc makePtrType(c: PContext, baseType: PType): PType =
|
||||
result = newTypeS(tyPtr, c)
|
||||
addSonSkipIntLit(result, baseType.AssertNotNil)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeVarType(c: PContext, baseType: PType): PType =
|
||||
result = newTypeS(tyVar, c)
|
||||
addSonSkipIntLit(result, baseType.AssertNotNil)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
result.addSonSkipIntLit(typ.AssertNotNil)
|
||||
result.addSonSkipIntLit(typ.assertNotNil)
|
||||
|
||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||
let typedesc = makeTypeDesc(c, typ)
|
||||
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
|
||||
return newSymNode(sym, info)
|
||||
|
||||
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||
result = newTypeS(tyFromExpr, c)
|
||||
result.n = n
|
||||
|
||||
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
||||
sons: seq[PType]): PType =
|
||||
result = newType(kind, getCurrOwner())
|
||||
result.sons = sons
|
||||
|
||||
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStaticExpr, n.info)
|
||||
result.sons = @[n]
|
||||
result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
|
||||
|
||||
proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
||||
result = newTypeS(tyAnd, c)
|
||||
result.sons = @[t1, t2]
|
||||
propagateToOwner(result, t1)
|
||||
propagateToOwner(result, t2)
|
||||
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
|
||||
proc makeOrType*(c: PContext, t1, t2: PType): PType =
|
||||
result = newTypeS(tyOr, c)
|
||||
result.sons = @[t1, t2]
|
||||
propagateToOwner(result, t1)
|
||||
propagateToOwner(result, t2)
|
||||
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
|
||||
proc makeNotType*(c: PContext, t1: PType): PType =
|
||||
result = newTypeS(tyNot, c)
|
||||
result.sons = @[t1]
|
||||
propagateToOwner(result, t1)
|
||||
result.flags.incl(t1.flags * {tfHasStatic})
|
||||
|
||||
proc nMinusOne*(n: PNode): PNode =
|
||||
result = newNode(nkCall, n.info, @[
|
||||
newSymNode(getSysMagic("<", mUnaryLt)),
|
||||
n])
|
||||
|
||||
# Remember to fix the procs below this one when you make changes!
|
||||
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
|
||||
let intType = getSysType(tyInt)
|
||||
result = newTypeS(tyRange, c)
|
||||
result.sons = @[intType]
|
||||
result.n = newNode(nkRange, n.info, @[
|
||||
newIntTypeNode(nkIntLit, 0, intType),
|
||||
makeStaticExpr(c, n.nMinusOne)])
|
||||
|
||||
template rangeHasStaticIf*(t: PType): bool =
|
||||
# this accepts the ranges's node
|
||||
t.n[1].kind == nkStaticExpr
|
||||
|
||||
template getStaticTypeFromRange*(t: PType): PType =
|
||||
t.n[1][0][1].typ
|
||||
|
||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||
result = newType(kind, getCurrOwner())
|
||||
|
||||
proc errorType*(c: PContext): PType =
|
||||
@@ -220,22 +286,22 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
|
||||
dest.owner = getCurrOwner()
|
||||
dest.size = - 1
|
||||
|
||||
proc makeRangeType*(c: PContext, first, last: biggestInt,
|
||||
info: TLineInfo): PType =
|
||||
proc makeRangeType*(c: PContext; first, last: BiggestInt;
|
||||
info: TLineInfo; intType = getSysType(tyInt)): PType =
|
||||
var n = newNodeI(nkRange, info)
|
||||
addSon(n, newIntNode(nkIntLit, first))
|
||||
addSon(n, newIntNode(nkIntLit, last))
|
||||
addSon(n, newIntTypeNode(nkIntLit, first, intType))
|
||||
addSon(n, newIntTypeNode(nkIntLit, last, intType))
|
||||
result = newTypeS(tyRange, c)
|
||||
result.n = n
|
||||
rawAddSon(result, getSysType(tyInt)) # basetype of range
|
||||
addSonSkipIntLit(result, intType) # basetype of range
|
||||
|
||||
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
|
||||
if s.kind in {skProc, skConverter, skMethod, skIterator}:
|
||||
if s.kind in {skProc, skConverter, skMethod, skIterator, skClosureIterator}:
|
||||
incl(s.flags, sfAddrTaken)
|
||||
# XXX add to 'c' for global analysis
|
||||
|
||||
proc illFormedAst*(n: PNode) =
|
||||
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc checkSonsLen*(n: PNode, length: int) =
|
||||
if sonsLen(n) != length: illFormedAst(n)
|
||||
|
||||
@@ -9,26 +9,39 @@
|
||||
|
||||
## This module implements destructors.
|
||||
|
||||
# included from sem.nim
|
||||
|
||||
# special marker values that indicates that we are
|
||||
# 1) AnalyzingDestructor: currently analyzing the type for destructor
|
||||
# generation (needed for recursive types)
|
||||
# 2) DestructorIsTrivial: completed the analysis before and determined
|
||||
# that the type has a trivial destructor
|
||||
var AnalyzingDestructor, DestructorIsTrivial: PSym
|
||||
new(AnalyzingDestructor)
|
||||
new(DestructorIsTrivial)
|
||||
var analyzingDestructor, destructorIsTrivial: PSym
|
||||
new(analyzingDestructor)
|
||||
new(destructorIsTrivial)
|
||||
|
||||
var
|
||||
destructorName = getIdent"destroy_"
|
||||
destructorParam = getIdent"this_"
|
||||
destructorPragma = newIdentNode(getIdent"destructor", UnknownLineInfo())
|
||||
destructorPragma = newIdentNode(getIdent"destructor", unknownLineInfo())
|
||||
rangeDestructorProc*: PSym
|
||||
|
||||
proc instantiateDestructor(c: PContext, typ: PType): bool
|
||||
proc instantiateDestructor(c: PContext, typ: PType): PType
|
||||
|
||||
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
||||
let t = s.typ.sons[1].skipTypes({tyVar})
|
||||
var t = s.typ.sons[1].skipTypes({tyVar})
|
||||
if t.kind == tyGenericInvokation:
|
||||
for i in 1 .. <t.sonsLen:
|
||||
if t.sons[i].kind != tyGenericParam:
|
||||
localError(n.info, errDestructorNotGenericEnough)
|
||||
return
|
||||
t = t.base
|
||||
elif t.kind == tyCompositeTypeClass:
|
||||
t = t.base
|
||||
if t.kind != tyGenericBody:
|
||||
localError(n.info, errDestructorNotGenericEnough)
|
||||
return
|
||||
|
||||
t.destructor = s
|
||||
# automatically insert calls to base classes' destructors
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
@@ -36,15 +49,19 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
||||
# when inheriting directly from object
|
||||
# there will be a single nil son
|
||||
if t.sons[i] == nil: continue
|
||||
if instantiateDestructor(c, t.sons[i]):
|
||||
let destructableT = instantiateDestructor(c, t.sons[i])
|
||||
if destructableT != nil:
|
||||
n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
|
||||
useSym(t.sons[i].destructor),
|
||||
useSym(destructableT.destructor),
|
||||
n.sons[paramsPos][1][0]]))
|
||||
|
||||
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
|
||||
if instantiateDestructor(c, field.typ):
|
||||
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode
|
||||
|
||||
proc destroySym(c: PContext, field: PSym, holder: PNode): PNode =
|
||||
let destructableT = instantiateDestructor(c, field.typ)
|
||||
if destructableT != nil:
|
||||
result = newNode(nkCall, field.info, @[
|
||||
useSym(field.typ.destructor),
|
||||
useSym(destructableT.destructor),
|
||||
newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
|
||||
|
||||
proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
|
||||
@@ -55,78 +72,83 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
|
||||
for i in countup(1, n.len - 1):
|
||||
# of A, B:
|
||||
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
|
||||
let recList = n[i].lastSon
|
||||
var destroyRecList = newNode(nkStmtList, n[i].info, @[])
|
||||
template addField(f: expr): stmt =
|
||||
let stmt = destroyField(c, f, holder)
|
||||
if stmt != nil:
|
||||
destroyRecList.addSon(stmt)
|
||||
inc nonTrivialFields
|
||||
|
||||
case recList.kind
|
||||
of nkSym:
|
||||
addField(recList.sym)
|
||||
of nkRecList:
|
||||
for j in countup(0, recList.len - 1):
|
||||
addField(recList[j].sym)
|
||||
|
||||
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
|
||||
if stmt == nil:
|
||||
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
caseBranch.addSon(destroyRecList)
|
||||
caseBranch.addSon(stmt)
|
||||
nonTrivialFields += stmt.len
|
||||
|
||||
result.addSon(caseBranch)
|
||||
|
||||
# maybe no fields were destroyed?
|
||||
if nonTrivialFields == 0:
|
||||
result = nil
|
||||
|
||||
|
||||
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
|
||||
template maybeAddLine(e: expr): stmt =
|
||||
let stmt = e
|
||||
if stmt != nil:
|
||||
if result == nil: result = newNode(nkStmtList)
|
||||
result.addSon(stmt)
|
||||
|
||||
case field.kind
|
||||
of nkRecCase:
|
||||
maybeAddLine destroyCase(c, field, holder)
|
||||
of nkSym:
|
||||
maybeAddLine destroySym(c, field.sym, holder)
|
||||
of nkRecList:
|
||||
for son in field:
|
||||
maybeAddLine destroyFieldOrFields(c, son, holder)
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
proc generateDestructor(c: PContext, t: PType): PNode =
|
||||
## generate a destructor for a user-defined object or tuple type
|
||||
## returns nil if the destructor turns out to be trivial
|
||||
|
||||
template addLine(e: expr): stmt =
|
||||
if result == nil: result = newNode(nkStmtList)
|
||||
result.addSon(e)
|
||||
|
||||
# XXX: This may be true for some C-imported types such as
|
||||
# Tposix_spawnattr
|
||||
if t.n == nil or t.n.sons == nil: return
|
||||
internalAssert t.n.kind == nkRecList
|
||||
let destructedObj = newIdentNode(destructorParam, UnknownLineInfo())
|
||||
let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
|
||||
# call the destructods of all fields
|
||||
for s in countup(0, t.n.sons.len - 1):
|
||||
case t.n.sons[s].kind
|
||||
of nkRecCase:
|
||||
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
|
||||
if stmt != nil: addLine(stmt)
|
||||
of nkSym:
|
||||
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
|
||||
if stmt != nil: addLine(stmt)
|
||||
else:
|
||||
internalAssert false
|
||||
result = destroyFieldOrFields(c, t.n, destructedObj)
|
||||
# base classes' destructors will be automatically called by
|
||||
# semProcAux for both auto-generated and user-defined destructors
|
||||
|
||||
proc instantiateDestructor(c: PContext, typ: PType): bool =
|
||||
# returns true if the type already had a user-defined
|
||||
# destructor or if the compiler generated a default
|
||||
# member-wise one
|
||||
var t = skipTypes(typ, {tyConst, tyMutable})
|
||||
proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||
# returns nil if a variable of type `typ` doesn't require a
|
||||
# destructor. Otherwise, returns the type, which holds the
|
||||
# destructor that must be used for the varialbe.
|
||||
# The destructor is either user-defined or automatically
|
||||
# generated by the compiler in a member-wise fashion.
|
||||
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
|
||||
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base
|
||||
else: t
|
||||
|
||||
if t.destructor != nil:
|
||||
if typeHoldingUserDefinition.destructor != nil:
|
||||
# XXX: This is not entirely correct for recursive types, but we need
|
||||
# it temporarily to hide the "destroy is already defined" problem
|
||||
return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
|
||||
if typeHoldingUserDefinition.destructor notin
|
||||
[analyzingDestructor, destructorIsTrivial]:
|
||||
return typeHoldingUserDefinition
|
||||
else:
|
||||
return nil
|
||||
|
||||
t = t.skipTypes({tyGenericInst})
|
||||
case t.kind
|
||||
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
|
||||
if instantiateDestructor(c, t.sons[0]):
|
||||
if instantiateDestructor(c, t.sons[0]) != nil:
|
||||
if rangeDestructorProc == nil:
|
||||
rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
|
||||
t.destructor = rangeDestructorProc
|
||||
return true
|
||||
return t
|
||||
else:
|
||||
return false
|
||||
return nil
|
||||
of tyTuple, tyObject:
|
||||
t.destructor = AnalyzingDestructor
|
||||
t.destructor = analyzingDestructor
|
||||
let generated = generateDestructor(c, t)
|
||||
if generated != nil:
|
||||
internalAssert t.sym != nil
|
||||
@@ -139,21 +161,21 @@ proc instantiateDestructor(c: PContext, typ: PType): bool =
|
||||
emptyNode,
|
||||
newNode(nkIdentDefs, i, @[
|
||||
newIdentNode(destructorParam, i),
|
||||
useSym(t.sym),
|
||||
symNodeFromType(c, makeVarType(c, t), t.sym.info),
|
||||
emptyNode]),
|
||||
]),
|
||||
newNode(nkPragma, i, @[destructorPragma]),
|
||||
emptyNode,
|
||||
generated
|
||||
])
|
||||
discard semProc(c, fullDef)
|
||||
internalAssert t.destructor != nil
|
||||
return true
|
||||
let semantizedDef = semProc(c, fullDef)
|
||||
t.destructor = semantizedDef[namePos].sym
|
||||
return t
|
||||
else:
|
||||
t.destructor = DestructorIsTrivial
|
||||
return false
|
||||
t.destructor = destructorIsTrivial
|
||||
return nil
|
||||
else:
|
||||
return false
|
||||
return nil
|
||||
|
||||
proc insertDestructors(c: PContext,
|
||||
varSection: PNode): tuple[outer, inner: PNode] =
|
||||
@@ -179,9 +201,11 @@ proc insertDestructors(c: PContext,
|
||||
varId = varSection[j][0]
|
||||
varTyp = varId.sym.typ
|
||||
info = varId.info
|
||||
|
||||
if varTyp != nil and instantiateDestructor(c, varTyp) and
|
||||
sfGlobal notin varId.sym.flags:
|
||||
|
||||
if varTyp == nil or sfGlobal in varId.sym.flags: continue
|
||||
let destructableT = instantiateDestructor(c, varTyp)
|
||||
|
||||
if destructableT != nil:
|
||||
var tryStmt = newNodeI(nkTryStmt, info)
|
||||
|
||||
if j < totalVars - 1:
|
||||
@@ -198,11 +222,11 @@ proc insertDestructors(c: PContext,
|
||||
else:
|
||||
result.inner = newNodeI(nkStmtList, info)
|
||||
tryStmt.addSon(result.inner)
|
||||
|
||||
|
||||
tryStmt.addSon(
|
||||
newNode(nkFinally, info, @[
|
||||
semStmt(c, newNode(nkCall, info, @[
|
||||
useSym(varTyp.destructor),
|
||||
useSym(destructableT.destructor),
|
||||
useSym(varId.sym)]))]))
|
||||
|
||||
result.outer = newNodeI(nkStmtList, info)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ proc getConstExpr*(m: PSym, n: PNode): PNode
|
||||
proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode
|
||||
proc leValueConv*(a, b: PNode): bool
|
||||
proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
|
||||
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode): PNode
|
||||
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
|
||||
proc newStrNodeT*(strVal: string, n: PNode): PNode
|
||||
|
||||
# implementation
|
||||
@@ -43,7 +43,10 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
||||
|
||||
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
|
||||
result = newFloatNode(nkFloatLit, floatVal)
|
||||
result.typ = n.typ
|
||||
if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
|
||||
result.typ = getFloatLitType(result)
|
||||
else:
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc newStrNodeT(strVal: string, n: PNode): PNode =
|
||||
@@ -51,7 +54,7 @@ proc newStrNodeT(strVal: string, n: PNode): PNode =
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc ordinalValToString(a: PNode): string =
|
||||
proc ordinalValToString*(a: PNode): string =
|
||||
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an
|
||||
# ordinal
|
||||
var x = getInt(a)
|
||||
@@ -63,14 +66,14 @@ proc ordinalValToString(a: PNode): string =
|
||||
of tyEnum:
|
||||
var n = t.n
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkSym: InternalError(a.info, "ordinalValToString")
|
||||
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
|
||||
var field = n.sons[i].sym
|
||||
if field.position == x:
|
||||
if field.ast == nil:
|
||||
return field.name.s
|
||||
else:
|
||||
return field.ast.strVal
|
||||
InternalError(a.info, "no symbol for ordinal value: " & $x)
|
||||
internalError(a.info, "no symbol for ordinal value: " & $x)
|
||||
else:
|
||||
result = $x
|
||||
|
||||
@@ -89,7 +92,7 @@ proc pickIntRange(a, b: PType): PType =
|
||||
proc isIntRangeOrLit(t: PType): bool =
|
||||
result = isIntRange(t) or isIntLit(t)
|
||||
|
||||
proc pickMinInt(n: PNode): biggestInt =
|
||||
proc pickMinInt(n: PNode): BiggestInt =
|
||||
if n.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = n.intVal
|
||||
elif isIntLit(n.typ):
|
||||
@@ -97,9 +100,9 @@ proc pickMinInt(n: PNode): biggestInt =
|
||||
elif isIntRange(n.typ):
|
||||
result = firstOrd(n.typ)
|
||||
else:
|
||||
InternalError(n.info, "pickMinInt")
|
||||
internalError(n.info, "pickMinInt")
|
||||
|
||||
proc pickMaxInt(n: PNode): biggestInt =
|
||||
proc pickMaxInt(n: PNode): BiggestInt =
|
||||
if n.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = n.intVal
|
||||
elif isIntLit(n.typ):
|
||||
@@ -107,17 +110,23 @@ proc pickMaxInt(n: PNode): biggestInt =
|
||||
elif isIntRange(n.typ):
|
||||
result = lastOrd(n.typ)
|
||||
else:
|
||||
InternalError(n.info, "pickMaxInt")
|
||||
internalError(n.info, "pickMaxInt")
|
||||
|
||||
proc makeRange(typ: PType, first, last: biggestInt): PType =
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, newIntNode(nkIntLit, min(first, last)))
|
||||
addSon(n, newIntNode(nkIntLit, max(first, last)))
|
||||
result = newType(tyRange, typ.owner)
|
||||
result.n = n
|
||||
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
||||
proc makeRange(typ: PType, first, last: BiggestInt): PType =
|
||||
let minA = min(first, last)
|
||||
let maxA = max(first, last)
|
||||
let lowerNode = newIntNode(nkIntLit, minA)
|
||||
if typ.kind == tyInt and minA == maxA:
|
||||
result = getIntLitType(lowerNode)
|
||||
else:
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, lowerNode)
|
||||
addSon(n, newIntNode(nkIntLit, maxA))
|
||||
result = newType(tyRange, typ.owner)
|
||||
result.n = n
|
||||
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
||||
|
||||
proc makeRangeF(typ: PType, first, last: biggestFloat): PType =
|
||||
proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
|
||||
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
|
||||
@@ -219,13 +228,40 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
commutativeOp(min)
|
||||
of mMaxI, mMaxI64:
|
||||
commutativeOp(max)
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
discard """
|
||||
mShlI, mShlI64,
|
||||
mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
|
||||
"""
|
||||
|
||||
proc evalIs(n, a: PNode): PNode =
|
||||
# XXX: This should use the standard isOpImpl
|
||||
internalAssert a.kind == nkSym and a.sym.kind == skType
|
||||
internalAssert n.sonsLen == 3 and
|
||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||
|
||||
let t1 = a.sym.typ
|
||||
|
||||
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
||||
case n[2].strVal.normalize
|
||||
of "closure":
|
||||
let t = skipTypes(t1, abstractRange)
|
||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||
t.callConv == ccClosure and
|
||||
tfIterator notin t.flags))
|
||||
of "iterator":
|
||||
let t = skipTypes(t1, abstractRange)
|
||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||
t.callConv == ccClosure and
|
||||
tfIterator in t.flags))
|
||||
else:
|
||||
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
|
||||
let t2 = n[2].typ
|
||||
var match = sameType(t1, t2)
|
||||
result = newIntNode(nkIntLit, ord(match))
|
||||
result.typ = n.typ
|
||||
|
||||
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
# b and c may be nil
|
||||
result = nil
|
||||
@@ -273,7 +309,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
|
||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
|
||||
else: InternalError(n.info, "constant folding for shl")
|
||||
else: internalError(n.info, "constant folding for shl")
|
||||
of mShrI, mShrI64:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
|
||||
@@ -281,7 +317,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
|
||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
||||
else: InternalError(n.info, "constant folding for shr")
|
||||
else: internalError(n.info, "constant folding for shr")
|
||||
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
|
||||
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
|
||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
||||
@@ -324,10 +360,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
||||
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n)
|
||||
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n)
|
||||
of mLeSet: result = newIntNodeT(Ord(containsSets(a, b)), n)
|
||||
of mEqSet: result = newIntNodeT(Ord(equalSets(a, b)), n)
|
||||
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
||||
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
||||
of mLtSet:
|
||||
result = newIntNodeT(Ord(containsSets(a, b) and not equalSets(a, b)), n)
|
||||
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
|
||||
of mMulSet:
|
||||
result = nimsets.intersectSets(a, b)
|
||||
result.info = n.info
|
||||
@@ -341,7 +377,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
result = nimsets.symdiffSets(a, b)
|
||||
result.info = n.info
|
||||
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
|
||||
of mInSet: result = newIntNodeT(Ord(inSet(a, b)), n)
|
||||
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
|
||||
of mRepr:
|
||||
# BUGFIX: we cannot eval mRepr here for reasons that I forgot.
|
||||
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
|
||||
@@ -360,19 +396,19 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
result = copyTree(a)
|
||||
result.typ = n.typ
|
||||
of mCompileOption:
|
||||
result = newIntNodeT(Ord(commands.testCompileOption(a.getStr, n.info)), n)
|
||||
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
|
||||
of mCompileOptionArg:
|
||||
result = newIntNodeT(Ord(
|
||||
result = newIntNodeT(ord(
|
||||
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
|
||||
of mNewString, mNewStringOfCap,
|
||||
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
|
||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
|
||||
mNLen..mNError, mEqRef, mSlurp, mStaticExec:
|
||||
nil
|
||||
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn:
|
||||
discard
|
||||
of mRand:
|
||||
result = newIntNodeT(math.random(a.getInt.int), n)
|
||||
else: InternalError(a.info, "evalOp(" & $m & ')')
|
||||
else: internalError(a.info, "evalOp(" & $m & ')')
|
||||
|
||||
proc getConstIfExpr(c: PSym, n: PNode): PNode =
|
||||
result = nil
|
||||
@@ -422,13 +458,13 @@ proc leValueConv(a, b: PNode): bool =
|
||||
case b.kind
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
|
||||
else: InternalError(a.info, "leValueConv")
|
||||
else: 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))
|
||||
else: InternalError(a.info, "leValueConv")
|
||||
else: InternalError(a.info, "leValueConv")
|
||||
else: internalError(a.info, "leValueConv")
|
||||
else: internalError(a.info, "leValueConv")
|
||||
|
||||
proc magicCall(m: PSym, n: PNode): PNode =
|
||||
if sonsLen(n) <= 1: return
|
||||
@@ -443,8 +479,6 @@ proc magicCall(m: PSym, n: PNode): PNode =
|
||||
if sonsLen(n) > 3:
|
||||
c = getConstExpr(m, n.sons[3])
|
||||
if c == nil: return
|
||||
else:
|
||||
b = nil
|
||||
result = evalOp(s.magic, n, a, b, c)
|
||||
|
||||
proc getAppType(n: PNode): PNode =
|
||||
@@ -457,9 +491,9 @@ proc getAppType(n: PNode): PNode =
|
||||
else:
|
||||
result = newStrNodeT("console", n)
|
||||
|
||||
proc rangeCheck(n: PNode, value: biggestInt) =
|
||||
proc rangeCheck(n: PNode, value: BiggestInt) =
|
||||
if value < firstOrd(n.typ) or value > lastOrd(n.typ):
|
||||
LocalError(n.info, errGenerated, "cannot convert " & $value &
|
||||
localError(n.info, errGenerated, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
|
||||
proc foldConv*(n, a: PNode; check = false): PNode =
|
||||
@@ -482,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
of tyOpenArray, tyVarargs, tyProc:
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
@@ -508,19 +542,19 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
|
||||
result = x.sons[int(idx)]
|
||||
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||
else:
|
||||
LocalError(n.info, errIndexOutOfBounds)
|
||||
of nkBracket, nkMetaNode:
|
||||
localError(n.info, errIndexOutOfBounds)
|
||||
of nkBracket:
|
||||
if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)]
|
||||
else: LocalError(n.info, errIndexOutOfBounds)
|
||||
else: localError(n.info, errIndexOutOfBounds)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
result = newNodeIT(nkCharLit, x.info, n.typ)
|
||||
if (idx >= 0) and (idx < len(x.strVal)):
|
||||
result.intVal = ord(x.strVal[int(idx)])
|
||||
elif idx == len(x.strVal):
|
||||
nil
|
||||
discard
|
||||
else:
|
||||
LocalError(n.info, errIndexOutOfBounds)
|
||||
else: nil
|
||||
localError(n.info, errIndexOutOfBounds)
|
||||
else: discard
|
||||
|
||||
proc foldFieldAccess(m: PSym, n: PNode): PNode =
|
||||
# a real field access; proc calls have already been transformed
|
||||
@@ -558,9 +592,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
var s = n.sym
|
||||
if s.kind == skEnumField:
|
||||
case s.kind
|
||||
of skEnumField:
|
||||
result = newIntNodeT(s.position, n)
|
||||
elif s.kind == skConst:
|
||||
of skConst:
|
||||
case s.magic
|
||||
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
||||
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
|
||||
@@ -578,10 +613,18 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of mNegInf: result = newFloatNodeT(NegInf, n)
|
||||
else:
|
||||
if sfFakeConst notin s.flags: result = copyTree(s.ast)
|
||||
elif s.kind in {skProc, skMethod}: # BUGFIX
|
||||
of {skProc, skMethod}:
|
||||
result = n
|
||||
elif s.kind in {skType, skGenericParam}:
|
||||
of skType:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
of skGenericParam:
|
||||
if s.typ.kind == tyStatic:
|
||||
if s.typ.n != nil:
|
||||
result = s.typ.n
|
||||
result.typ = s.typ.sons[0]
|
||||
else:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else: discard
|
||||
of nkCharLit..nkNilLit:
|
||||
result = copyNode(n)
|
||||
of nkIfExpr:
|
||||
@@ -593,11 +636,12 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
try:
|
||||
case s.magic
|
||||
of mNone:
|
||||
return # XXX: if it has no sideEffect, it should be evaluated
|
||||
# If it has no sideEffect, it should be evaluated. But not here.
|
||||
return
|
||||
of mSizeOf:
|
||||
var a = n.sons[1]
|
||||
if computeSize(a.typ) < 0:
|
||||
LocalError(a.info, errCannotEvalXBecauseIncompletelyDefined,
|
||||
localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
|
||||
"sizeof")
|
||||
result = nil
|
||||
elif skipTypes(a.typ, typedescInst).kind in
|
||||
@@ -625,16 +669,24 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
result = newIntNodeT(sonsLen(a), n)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
of mLengthArray:
|
||||
# It doesn't matter if the argument is const or not for mLengthArray.
|
||||
# This fixes bug #544.
|
||||
result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
|
||||
of mAstToStr:
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||
of mConStrStr:
|
||||
result = foldConStrStr(m, n)
|
||||
of mIs:
|
||||
let a = getConstExpr(m, n[1])
|
||||
if a != nil and a.kind == nkSym and a.sym.kind == skType:
|
||||
result = evalIs(n, a)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
except EOverflow:
|
||||
LocalError(n.info, errOverOrUnderflow)
|
||||
localError(n.info, errOverOrUnderflow)
|
||||
except EDivByZero:
|
||||
LocalError(n.info, errConstantDivisionByZero)
|
||||
localError(n.info, errConstantDivisionByZero)
|
||||
of nkAddr:
|
||||
var a = getConstExpr(m, n.sons[0])
|
||||
if a != nil:
|
||||
@@ -690,7 +742,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
result = a # a <= x and x <= b
|
||||
result.typ = n.typ
|
||||
else:
|
||||
LocalError(n.info, errGenerated, `%`(
|
||||
localError(n.info, errGenerated, `%`(
|
||||
msgKindToString(errIllegalConvFromXtoY),
|
||||
[typeToString(n.sons[0].typ), typeToString(n.typ)]))
|
||||
of nkStringToCString, nkCStringToString:
|
||||
@@ -712,4 +764,4 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of nkBracketExpr: result = foldArrayAccess(m, n)
|
||||
of nkDotExpr: result = foldFieldAccess(m, n)
|
||||
else:
|
||||
nil
|
||||
discard
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -17,11 +17,6 @@
|
||||
|
||||
# included from sem.nim
|
||||
|
||||
type
|
||||
TSemGenericFlag = enum
|
||||
withinBind, withinTypeDesc, withinMixin
|
||||
TSemGenericFlags = set[TSemGenericFlag]
|
||||
|
||||
proc getIdentNode(n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkPostfix: result = getIdentNode(n.sons[1])
|
||||
@@ -31,8 +26,6 @@ proc getIdentNode(n: PNode): PNode =
|
||||
illFormedAst(n)
|
||||
result = n
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode
|
||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode =
|
||||
@@ -49,17 +42,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
result = n
|
||||
of skProc, skMethod, skIterator, skConverter:
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
let n = fixImmediateParams(n)
|
||||
result = semTemplateExpr(c, n, s, false)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
result = semMacroExpr(c, n, n, s, false)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skGenericParam:
|
||||
@@ -73,7 +66,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
result = n
|
||||
else: result = newSymNode(s, n.info)
|
||||
|
||||
proc Lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode =
|
||||
result = n
|
||||
let ident = considerAcc(n)
|
||||
@@ -96,10 +89,10 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
if gCmd == cmdIdeTools: suggestStmt(c, n)
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
result = Lookup(c, n, flags, ctx)
|
||||
result = lookup(c, n, flags, ctx)
|
||||
of nkDotExpr:
|
||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||
var s = QualifiedLookUp(c, n, luf)
|
||||
var s = qualifiedLookUp(c, n, luf)
|
||||
if s != nil: result = semGenericStmtSymbol(c, n, s)
|
||||
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
|
||||
of nkEmpty, nkSym..nkNilLit:
|
||||
@@ -110,7 +103,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
# not work. Copying the symbol does not work either because we're already
|
||||
# the owner of the symbol! What we need to do is to copy the symbol
|
||||
# in the generic instantiation process...
|
||||
nil
|
||||
discard
|
||||
of nkBind:
|
||||
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
|
||||
of nkMixinStmt:
|
||||
@@ -119,7 +112,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1)
|
||||
let fn = n.sons[0]
|
||||
var s = qualifiedLookup(c, fn, {})
|
||||
var s = qualifiedLookUp(c, fn, {})
|
||||
if s == nil and withinMixin notin flags and
|
||||
fn.kind in {nkIdent, nkAccQuoted} and considerAcc(fn).id notin ctx:
|
||||
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
||||
@@ -133,14 +126,14 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
case s.kind
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
result = semMacroExpr(c, n, n, s, false)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
else:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
result = n
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
let n = fixImmediateParams(n)
|
||||
result = semTemplateExpr(c, n, s, false)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
else:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
result = n
|
||||
@@ -148,7 +141,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
# symbol lookup ...
|
||||
of skUnknown, skParam:
|
||||
# Leave it as an identifier.
|
||||
of skProc, skMethod, skIterator, skConverter:
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
first = 1
|
||||
of skGenericParam:
|
||||
@@ -219,22 +212,20 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
|
||||
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
|
||||
ctx)
|
||||
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 countup(0, L-3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
of nkGenericParams:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
|
||||
ctx)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L-3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
@@ -242,7 +233,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkConstDef): IllFormedAst(a)
|
||||
if (a.kind != nkConstDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||
@@ -251,13 +242,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): IllFormedAst(a)
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): IllFormedAst(a)
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
if a.sons[1].kind != nkEmpty:
|
||||
openScope(c)
|
||||
@@ -278,18 +269,17 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
else: illFormedAst(n)
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||
of nkObjectTy, nkTupleTy:
|
||||
nil
|
||||
discard
|
||||
of nkFormalParams:
|
||||
checkMinSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
|
||||
ctx)
|
||||
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 countup(0, L-3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
@@ -311,8 +301,8 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
else: body = n.sons[bodyPos]
|
||||
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
|
||||
closeScope(c)
|
||||
of nkPragma, nkPragmaExpr: nil
|
||||
of nkExprColonExpr:
|
||||
of nkPragma, nkPragmaExpr: discard
|
||||
of nkExprColonExpr, nkExprEqExpr:
|
||||
checkMinSonsLen(n, 2)
|
||||
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
else:
|
||||
|
||||
@@ -13,32 +13,31 @@
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
entry: var TInstantiation) =
|
||||
if n.kind != nkGenericParams:
|
||||
InternalError(n.info, "instantiateGenericParamList; no generic params")
|
||||
internalError(n.info, "instantiateGenericParamList; no generic params")
|
||||
newSeq(entry.concreteTypes, n.len)
|
||||
for i in countup(0, n.len - 1):
|
||||
var a = n.sons[i]
|
||||
for i, a in n.pairs:
|
||||
if a.kind != nkSym:
|
||||
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
internalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
var q = a.sym
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||
continue
|
||||
var s = newSym(skType, q.name, getCurrOwner(), q.info)
|
||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||
var t = PType(IdTableGet(pt, q.typ))
|
||||
var t = PType(idTableGet(pt, q.typ))
|
||||
if t == nil:
|
||||
if tfRetType in q.typ.flags:
|
||||
# keep the generic type and allow the return type to be bound
|
||||
# later by semAsgn in return type inference scenario
|
||||
t = q.typ
|
||||
else:
|
||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||
localError(a.info, errCannotInstantiateX, s.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericParam:
|
||||
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||
internalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||
elif t.kind == tyGenericInvokation:
|
||||
#t = instGenericContainer(c, a, t)
|
||||
t = generateTypeInstance(c, pt, a, t)
|
||||
#t = ReplaceTypeVarsT(cl, t)
|
||||
t.flags.incl tfInstantiated
|
||||
s.typ = t
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = t
|
||||
@@ -47,10 +46,10 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
||||
if a.concreteTypes.len == b.concreteTypes.len:
|
||||
for i in 0..a.concreteTypes.high:
|
||||
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
||||
flags = {TypeDescExactMatch}): return
|
||||
flags = {ExactTypeDescValues}): return
|
||||
result = true
|
||||
|
||||
proc GenericCacheGet(genericSym: Psym, entry: TInstantiation): PSym =
|
||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
|
||||
if genericSym.procInstCache != nil:
|
||||
for inst in genericSym.procInstCache:
|
||||
if sameInstantiation(entry, inst[]):
|
||||
@@ -75,31 +74,42 @@ proc removeDefaultParamValues(n: PNode) =
|
||||
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
|
||||
# we need to create a fresh set of gensym'ed symbols:
|
||||
if n.kind == nkSym and sfGenSym in n.sym.flags:
|
||||
var x = PSym(IdTableGet(symMap, n.sym))
|
||||
var x = PSym(idTableGet(symMap, n.sym))
|
||||
if x == nil:
|
||||
x = copySym(n.sym, false)
|
||||
x.owner = owner
|
||||
IdTablePut(symMap, n.sym, x)
|
||||
idTablePut(symMap, n.sym, x)
|
||||
n.sym = x
|
||||
else:
|
||||
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
|
||||
|
||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||
|
||||
proc addProcDecls(c: PContext, fn: PSym) =
|
||||
# get the proc itself in scope (e.g. for recursion)
|
||||
addDecl(c, fn)
|
||||
|
||||
for i in 1 .. <fn.typ.n.len:
|
||||
var param = fn.typ.n.sons[i].sym
|
||||
param.owner = fn
|
||||
addParamOrResult(c, param, fn.kind)
|
||||
|
||||
maybeAddResult(c, fn, fn.ast)
|
||||
|
||||
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
inc c.inGenericInst
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
addDecl(c, result)
|
||||
pushProcCon(c, result)
|
||||
maybeAddResult(c, result, n)
|
||||
var b = n.sons[bodyPos]
|
||||
var symMap: TIdTable
|
||||
InitIdTable symMap
|
||||
initIdTable symMap
|
||||
freshGenSyms(b, result, symMap)
|
||||
b = semProcBody(c, b)
|
||||
b = hloBody(c, b)
|
||||
n.sons[bodyPos] = transformBody(c.module, b, result)
|
||||
#echo "code instantiated ", result.name.s
|
||||
excl(result.flags, sfForward)
|
||||
popProcCon(c)
|
||||
dec c.inGenericInst
|
||||
|
||||
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
for i in countup(0, c.generics.len - 1):
|
||||
@@ -109,8 +119,6 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
openScope(c)
|
||||
var n = oldPrc.ast
|
||||
n.sons[bodyPos] = copyTree(s.getBody)
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
addParams(c, oldPrc.typ.n, oldPrc.kind)
|
||||
instantiateBody(c, n, oldPrc)
|
||||
closeScope(c)
|
||||
popInfoContext()
|
||||
@@ -118,51 +126,99 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||
if {sfNoSideEffect, sfSideEffect} * s.flags ==
|
||||
{sfNoSideEffect, sfSideEffect}:
|
||||
LocalError(s.info, errXhasSideEffects, s.name.s)
|
||||
elif sfThread in s.flags and semthreads.needsGlobalAnalysis() and
|
||||
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
||||
c.threadEntries.add(s)
|
||||
localError(s.info, errXhasSideEffects, s.name.s)
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
allowMetaTypes = false): PType =
|
||||
var cl: TReplTypeVars
|
||||
initIdTable(cl.symMap)
|
||||
initIdTable(cl.typeMap)
|
||||
initIdTable(cl.localCache)
|
||||
cl.info = info
|
||||
cl.c = c
|
||||
cl.allowMetaTypes = allowMetaTypes
|
||||
result = replaceTypeVarsT(cl, header)
|
||||
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||
result = instGenericContainer(c, n.info, header)
|
||||
|
||||
proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
prc: PSym, info: TLineInfo) =
|
||||
# XXX: Instantiates a generic proc signature, while at the same
|
||||
# time adding the instantiated proc params into the current scope.
|
||||
# This is necessary, because the instantiation process may refer to
|
||||
# these params in situations like this:
|
||||
# proc foo[Container](a: Container, b: a.type.Item): type(b.x)
|
||||
#
|
||||
# Alas, doing this here is probably not enough, because another
|
||||
# proc signature could appear in the params:
|
||||
# proc foo[T](a: proc (x: T, b: type(x.y))
|
||||
#
|
||||
# The solution would be to move this logic into semtypinst, but
|
||||
# at this point semtypinst have to become part of sem, because it
|
||||
# will need to use openScope, addDecl, etc
|
||||
#
|
||||
addDecl(c, prc)
|
||||
|
||||
pushInfoContext(info)
|
||||
var cl = initTypeVars(c, pt, info)
|
||||
var result = instCopyType(cl, prc.typ)
|
||||
let originalParams = result.n
|
||||
result.n = originalParams.shallowCopy
|
||||
|
||||
for i in 1 .. <result.len:
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.sons[i])
|
||||
let param = replaceTypeVarsN(cl, originalParams[i])
|
||||
result.n.sons[i] = param
|
||||
if param.kind == nkSym:
|
||||
# XXX: this won't be true for void params
|
||||
# implement pass-through of void params and
|
||||
# the "sort by distance to point" container
|
||||
param.sym.owner = prc
|
||||
addDecl(c, param.sym)
|
||||
|
||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||
result.n.sons[0] = originalParams[0].copyTree
|
||||
|
||||
eraseVoidParams(result)
|
||||
skipIntLiteralParams(result)
|
||||
|
||||
prc.typ = result
|
||||
maybeAddResult(c, prc, prc.ast)
|
||||
popInfoContext()
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
# no need to instantiate generic templates/macros:
|
||||
if fn.kind in {skTemplate, skMacro}: return fn
|
||||
|
||||
# generates an instantiated proc
|
||||
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
|
||||
inc(c.InstCounter)
|
||||
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
|
||||
inc(c.instCounter)
|
||||
# careful! we copy the whole AST including the possibly nil body!
|
||||
var n = copyTree(fn.ast)
|
||||
# NOTE: for access of private fields within generics from a different module
|
||||
# we set the friend module:
|
||||
var oldFriend = c.friendModule
|
||||
c.friendModule = getModule(fn)
|
||||
#let oldScope = c.currentScope
|
||||
#c.currentScope = fn.scope
|
||||
result = copySym(fn, false)
|
||||
incl(result.flags, sfFromGeneric)
|
||||
# keep the owner if it's an inner proc (for proper closure transformations):
|
||||
if fn.owner.kind == skModule:
|
||||
result.owner = getCurrOwner().owner
|
||||
result.owner = fn
|
||||
result.ast = n
|
||||
pushOwner(result)
|
||||
openScope(c)
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
InternalError(n.info, "generateInstance")
|
||||
internalAssert n.sons[genericParamsPos].kind != nkEmpty
|
||||
n.sons[namePos] = newSymNode(result)
|
||||
pushInfoContext(info)
|
||||
var entry = TInstantiation.new
|
||||
entry.sym = result
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
||||
pushProcCon(c, result)
|
||||
instantiateProcType(c, pt, result, info)
|
||||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
# semantic checking for the parameters:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
removeDefaultParamValues(n.sons[ParamsPos])
|
||||
semParamList(c, n.sons[ParamsPos], nil, result)
|
||||
else:
|
||||
result.typ = newTypeS(tyProc, c)
|
||||
rawAddSon(result.typ, nil)
|
||||
result.typ.callConv = fn.typ.callConv
|
||||
if result.kind == skIterator: result.typ.flags.incl(tfIterator)
|
||||
var oldPrc = GenericCacheGet(fn, entry[])
|
||||
var oldPrc = genericCacheGet(fn, entry[])
|
||||
if oldPrc == nil:
|
||||
fn.procInstCache.safeAdd(entry)
|
||||
c.generics.add(makeInstPair(fn, entry))
|
||||
@@ -170,24 +226,16 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||
if isNil(n.sons[bodyPos]):
|
||||
n.sons[bodyPos] = copyTree(fn.getBody)
|
||||
if fn.kind != skTemplate:
|
||||
instantiateBody(c, n, result)
|
||||
sideEffectsCheck(c, result)
|
||||
ParamsTypeCheck(c, result.typ)
|
||||
instantiateBody(c, n, result)
|
||||
sideEffectsCheck(c, result)
|
||||
paramsTypeCheck(c, result.typ)
|
||||
else:
|
||||
result = oldPrc
|
||||
popProcCon(c)
|
||||
popInfoContext()
|
||||
closeScope(c) # close scope for parameters
|
||||
popOwner()
|
||||
#c.currentScope = oldScope
|
||||
c.friendModule = oldFriend
|
||||
dec(c.InstCounter)
|
||||
dec(c.instCounter)
|
||||
if result.kind == skMethod: finishMethod(c, result)
|
||||
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||
var cl: TReplTypeVars
|
||||
InitIdTable(cl.symMap)
|
||||
InitIdTable(cl.typeMap)
|
||||
cl.info = n.info
|
||||
cl.c = c
|
||||
result = ReplaceTypeVarsT(cl, header)
|
||||
|
||||
|
||||
89
compiler/semmacrosanity.nim
Normal file
89
compiler/semmacrosanity.nim
Normal file
@@ -0,0 +1,89 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Implements type sanity checking for ASTs resulting from macros. Lots of
|
||||
## room for improvement here.
|
||||
|
||||
import ast, astalgo, msgs, types
|
||||
|
||||
proc ithField(n: PNode, field: int): PSym =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = ithField(n.sons[i], field-i)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
|
||||
result = ithField(n.sons[0], field-1)
|
||||
if result != nil: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = ithField(lastSon(n.sons[i]), field-1)
|
||||
if result != nil: return
|
||||
else: internalError(n.info, "ithField(record case branch)")
|
||||
of nkSym:
|
||||
if field == 0: result = n.sym
|
||||
else: discard
|
||||
|
||||
proc annotateType*(n: PNode, t: PType) =
|
||||
let x = t.skipTypes(abstractInst)
|
||||
# Note: x can be unequal to t and we need to be careful to use 't'
|
||||
# to not to skip tyGenericInst
|
||||
case n.kind
|
||||
of nkPar:
|
||||
if x.kind == tyObject:
|
||||
n.typ = t
|
||||
for i in 0 .. <n.len:
|
||||
let field = x.n.ithField(i)
|
||||
if field.isNil: globalError n.info, "invalid field at index " & $i
|
||||
else: annotateType(n.sons[i], field.typ)
|
||||
elif x.kind == tyTuple:
|
||||
n.typ = t
|
||||
for i in 0 .. <n.len:
|
||||
if i >= x.len: globalError n.info, "invalid field at index " & $i
|
||||
else: annotateType(n.sons[i], x.sons[i])
|
||||
elif x.kind == tyProc and x.callConv == ccClosure:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(n.info, "() must have an object or tuple type")
|
||||
of nkBracket:
|
||||
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
|
||||
n.typ = t
|
||||
for m in n: annotateType(m, x.elemType)
|
||||
else:
|
||||
globalError(n.info, "[] must have some form of array type")
|
||||
of nkCurly:
|
||||
if x.kind in {tySet}:
|
||||
n.typ = t
|
||||
for m in n: annotateType(m, x.elemType)
|
||||
else:
|
||||
globalError(n.info, "{} must have the set type")
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
if x.kind in {tyFloat..tyFloat128}:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(n.info, "float literal must have some float type")
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(n.info, "integer literal must have some int type")
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if x.kind in {tyString, tyCString}:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(n.info, "string literal must be of some string type")
|
||||
of nkNilLit:
|
||||
if x.kind in NilableTypes:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(n.info, "nil literal must be of some pointer type")
|
||||
else: discard
|
||||
@@ -18,7 +18,7 @@ proc expectIntLit(c: PContext, n: PNode): int =
|
||||
let x = c.semConstExpr(c, n)
|
||||
case x.kind
|
||||
of nkIntLit..nkInt64Lit: result = int(x.intVal)
|
||||
else: LocalError(n.info, errIntLiteralExpected)
|
||||
else: localError(n.info, errIntLiteralExpected)
|
||||
|
||||
proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||
result = newNodeIT(nkPar, n.info, n.typ)
|
||||
@@ -26,21 +26,34 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||
let useFullPaths = expectIntLit(c, n.sons[2])
|
||||
let info = getInfoContext(idx)
|
||||
var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
|
||||
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.ToFilename
|
||||
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename
|
||||
var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
|
||||
line.intVal = ToLinenumber(info)
|
||||
line.intVal = toLinenumber(info)
|
||||
result.add(filename)
|
||||
result.add(line)
|
||||
|
||||
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
||||
let typ = operand.skipTypes({tyTypeDesc})
|
||||
case trait.sym.name.s.normalize
|
||||
of "name":
|
||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||
result.typ = newType(tyString, context)
|
||||
result.info = trait.info
|
||||
of "arity":
|
||||
result = newIntNode(nkIntLit, typ.n.len-1)
|
||||
result.typ = newType(tyInt, context)
|
||||
result.info = trait.info
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||
checkMinSonsLen(n, 2)
|
||||
internalAssert n.sons[1].kind == nkSym
|
||||
let typArg = n.sons[1].sym
|
||||
if typArg.kind == skType or
|
||||
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
|
||||
let t = n.sons[1].typ
|
||||
internalAssert t != nil and t.kind == tyTypeDesc
|
||||
if t.sonsLen > 0:
|
||||
# This is either a type known to sem or a typedesc
|
||||
# param to a regular proc (again, known at instantiation)
|
||||
result = evalTypeTrait(n, GetCurrOwner())
|
||||
result = evalTypeTrait(n[0], t, getCurrOwner())
|
||||
else:
|
||||
# a typedesc variable, pass unmodified to evals
|
||||
result = n
|
||||
@@ -56,23 +69,23 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||
|
||||
let sl = semConstExpr(c, n.sons[1])
|
||||
if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
||||
LocalError(n.sons[1].info, errStringLiteralExpected)
|
||||
localError(n.sons[1].info, errStringLiteralExpected)
|
||||
return errorNode(c, n)
|
||||
|
||||
let isMixin = semConstExpr(c, n.sons[2])
|
||||
if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
|
||||
isMixin.intVal > high(TSymChoiceRule).int:
|
||||
LocalError(n.sons[2].info, errConstExprExpected)
|
||||
localError(n.sons[2].info, errConstExprExpected)
|
||||
return errorNode(c, n)
|
||||
|
||||
let id = newIdentNode(getIdent(sl.strVal), n.info)
|
||||
let s = QualifiedLookUp(c, id)
|
||||
let s = qualifiedLookUp(c, id)
|
||||
if s != nil:
|
||||
# we need to mark all symbols:
|
||||
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
|
||||
result.add(sc)
|
||||
else:
|
||||
LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
|
||||
localError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
|
||||
|
||||
proc semLocals(c: PContext, n: PNode): PNode =
|
||||
var counter = 0
|
||||
@@ -88,7 +101,7 @@ proc semLocals(c: PContext, n: PNode): PNode =
|
||||
#if it.owner != c.p.owner: return result
|
||||
if it.kind in skLocalVars and
|
||||
it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
|
||||
{tyVarargs, tyOpenArray, tyTypeDesc, tyExpr, tyStmt, tyEmpty}:
|
||||
{tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
|
||||
|
||||
var field = newSym(skField, it.name, getCurrOwner(), n.info)
|
||||
field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
|
||||
@@ -113,6 +126,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result.typ = getSysType(tyString)
|
||||
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||
of mOrd: result = semOrd(c, n)
|
||||
of mHigh: result = semLowHigh(c, n, mHigh)
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mNBindSym: result = semBindSym(c, n)
|
||||
of mLocals: result = semLocals(c, n)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user