mirror of
https://github.com/janet-lang/janet
synced 2025-10-28 06:07:43 +00:00
Compare commits
3057 Commits
core-image
...
op_subtrac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b6371e03d | ||
|
|
b5d3c87253 | ||
|
|
f73b8c550a | ||
|
|
5437744126 | ||
|
|
5a5e70b001 | ||
|
|
348a5bc0a9 | ||
|
|
026c64fa01 | ||
|
|
e38663c457 | ||
|
|
117c741c29 | ||
|
|
9bc5bec9f1 | ||
|
|
a5f4e4d328 | ||
|
|
db0abfde72 | ||
|
|
edf263bcb5 | ||
|
|
60fba585e3 | ||
|
|
ebb6fe5be3 | ||
|
|
d91c95bf92 | ||
|
|
2007438424 | ||
|
|
81423635ad | ||
|
|
58d297364a | ||
|
|
db902c90c4 | ||
|
|
42ccd0f790 | ||
|
|
20ec6f574e | ||
|
|
b3db367ae7 | ||
|
|
8a62c742e6 | ||
|
|
b125cbeac9 | ||
|
|
3f7a2c2197 | ||
|
|
f6248369fe | ||
|
|
c83f3ec097 | ||
|
|
0cd00da354 | ||
|
|
4b7b285aa9 | ||
|
|
d63379e777 | ||
|
|
b219b146fa | ||
|
|
ff90b81ec3 | ||
|
|
9120eaef79 | ||
|
|
1ccd879916 | ||
|
|
f977ace7f8 | ||
|
|
c3f4dc0c15 | ||
|
|
78eed9b11c | ||
|
|
3a4d56afca | ||
|
|
63bb93fc07 | ||
|
|
5a39a04a79 | ||
|
|
2fde34b519 | ||
|
|
1ef5c038db | ||
|
|
e2459cfb47 | ||
|
|
cfffc0bcf1 | ||
|
|
7272f43191 | ||
|
|
2a7ea27bb7 | ||
|
|
32c5b816ae | ||
|
|
e54ea7a1d8 | ||
|
|
1077efd03a | ||
|
|
f9ab91511d | ||
|
|
2c3ca2984e | ||
|
|
94722e566c | ||
|
|
163f7ee85d | ||
|
|
52d3470cbe | ||
|
|
0bd6e85c61 | ||
|
|
e35c6b876f | ||
|
|
9a2897e741 | ||
|
|
70b2e8179d | ||
|
|
5317edc65d | ||
|
|
866d83579e | ||
|
|
a238391b36 | ||
|
|
5e152d30db | ||
|
|
57c954783d | ||
|
|
b5407ac708 | ||
|
|
472ec730b5 | ||
|
|
8c819b1f91 | ||
|
|
528a516390 | ||
|
|
6509e37c84 | ||
|
|
649173f661 | ||
|
|
1efb0adb35 | ||
|
|
88a8e2c1df | ||
|
|
bb4ff05d35 | ||
|
|
dd3b601c87 | ||
|
|
e22d101a62 | ||
|
|
4b3c813f5a | ||
|
|
67f375bea2 | ||
|
|
88ba99b87e | ||
|
|
53447e9d0b | ||
|
|
c4c86f8671 | ||
|
|
658941d26d | ||
|
|
e4bf27b01c | ||
|
|
7d48b75f81 | ||
|
|
5f56bf836c | ||
|
|
c0f5f97ddb | ||
|
|
15177ac2e9 | ||
|
|
8360bc93ac | ||
|
|
e0ea844d50 | ||
|
|
9675411f35 | ||
|
|
e97299fc65 | ||
|
|
26a113927e | ||
|
|
d0aa7ef590 | ||
|
|
5de889419f | ||
|
|
0fcbda2da7 | ||
|
|
14e33c295f | ||
|
|
644ac8caf8 | ||
|
|
77189b6e66 | ||
|
|
4f8f7f66ee | ||
|
|
b099bd97f2 | ||
|
|
961c6ea15a | ||
|
|
9c97d8f648 | ||
|
|
ad7bf80611 | ||
|
|
40080b23ae | ||
|
|
7acb5c63e0 | ||
|
|
fcca9bbab3 | ||
|
|
dbb2187425 | ||
|
|
82e51f9e81 | ||
|
|
4782a76bca | ||
|
|
d13788a4ed | ||
|
|
e64a0175b1 | ||
|
|
4aca94154f | ||
|
|
ac5f118dac | ||
|
|
a2812ec5eb | ||
|
|
70f13f1b62 | ||
|
|
77e62a25cb | ||
|
|
09345ec786 | ||
|
|
bad73baf98 | ||
|
|
3602f5aa5d | ||
|
|
672b705faf | ||
|
|
64e3cdeb2b | ||
|
|
909c906080 | ||
|
|
71bde11e95 | ||
|
|
fc20fbed92 | ||
|
|
e6b7c85c37 | ||
|
|
b3a92363f8 | ||
|
|
e9f2d1aca7 | ||
|
|
b4e3dbf331 | ||
|
|
c3620786cf | ||
|
|
41943746e4 | ||
|
|
176e816b8c | ||
|
|
50a19bd870 | ||
|
|
57b751b994 | ||
|
|
77732a8f44 | ||
|
|
c47c2e538d | ||
|
|
cc5545277d | ||
|
|
63353b98cd | ||
|
|
4dfc869b8a | ||
|
|
b4b1c7d80b | ||
|
|
e53c03028f | ||
|
|
8680aef42f | ||
|
|
c3fd71d643 | ||
|
|
30c47d685d | ||
|
|
80db682109 | ||
|
|
e8e5f66f4c | ||
|
|
aaf3d08bcd | ||
|
|
61132d6c40 | ||
|
|
9cc0645a1e | ||
|
|
fc8c6a429e | ||
|
|
2f966883d9 | ||
|
|
320ba80ca1 | ||
|
|
b621d4dd2e | ||
|
|
56d927c72d | ||
|
|
53afc2e50a | ||
|
|
89debac8f6 | ||
|
|
f2197fa2d8 | ||
|
|
a6a097c111 | ||
|
|
c3e28bc924 | ||
|
|
8d78fb1f6b | ||
|
|
148917d4ca | ||
|
|
d8cf9bf942 | ||
|
|
d6f5a060ed | ||
|
|
692b6ef8ac | ||
|
|
ac5f1fe1be | ||
|
|
0f35acade1 | ||
|
|
56d72ec4c5 | ||
|
|
71d51c160d | ||
|
|
0b58e505ee | ||
|
|
2a6c615bec | ||
|
|
ab8c5a0b5f | ||
|
|
68c35feaea | ||
|
|
88d0c2ca0f | ||
|
|
398833ebe3 | ||
|
|
358f5a03bf | ||
|
|
fba1fdabe4 | ||
|
|
d42afd21e5 | ||
|
|
20ada86761 | ||
|
|
3b353f1855 | ||
|
|
1467ab4f93 | ||
|
|
7e65c2bdad | ||
|
|
84a4e3e98a | ||
|
|
bcbeedb001 | ||
|
|
e04b103b5d | ||
|
|
ac75b94679 | ||
|
|
d3bb06cfd6 | ||
|
|
5cd729c4c1 | ||
|
|
c9fd2bdf39 | ||
|
|
e4be5992b3 | ||
|
|
2ac4988f1b | ||
|
|
19f14adb9e | ||
|
|
86de039492 | ||
|
|
2360164e4f | ||
|
|
c93ddceadb | ||
|
|
cd19dec44a | ||
|
|
53ba9c800a | ||
|
|
cabbaded68 | ||
|
|
9bb589f827 | ||
|
|
c3a06686c2 | ||
|
|
7d57f87007 | ||
|
|
4cc4a9d38b | ||
|
|
02c7cd0194 | ||
|
|
696efcb9e2 | ||
|
|
6e9cde8ac1 | ||
|
|
a9fae49671 | ||
|
|
440af9fd64 | ||
|
|
347721ae40 | ||
|
|
daea91044c | ||
|
|
4ed3f2c662 | ||
|
|
3641c8f60a | ||
|
|
e4b68cd940 | ||
|
|
b8c936e2fe | ||
|
|
83cd519702 | ||
|
|
54b54f85f3 | ||
|
|
ccd874fe4e | ||
|
|
9dc7e8ed3a | ||
|
|
485099fd6e | ||
|
|
d359c6b43e | ||
|
|
d9ed7a77f8 | ||
|
|
4238a4ca6a | ||
|
|
0902a5a981 | ||
|
|
f3192303ab | ||
|
|
bef5bd72c2 | ||
|
|
b6175e4296 | ||
|
|
3858b2e177 | ||
|
|
9a76e77981 | ||
|
|
8182d640cd | ||
|
|
1c6fda1a5c | ||
|
|
c51db1cf2f | ||
|
|
4e7930fc4c | ||
|
|
3563f8ccdb | ||
|
|
575af763f6 | ||
|
|
8b16b9b246 | ||
|
|
01aab66667 | ||
|
|
aa5c987a94 | ||
|
|
75229332c8 | ||
|
|
9d5b1ba838 | ||
|
|
f27b225b34 | ||
|
|
3c523d66e9 | ||
|
|
1144c27c54 | ||
|
|
b442b21d3f | ||
|
|
746ff5307d | ||
|
|
ef85b24d8f | ||
|
|
c55d93512b | ||
|
|
2e38f9ba61 | ||
|
|
1cadff8e58 | ||
|
|
d1eba60ba8 | ||
|
|
057dccad8f | ||
|
|
4285200b4b | ||
|
|
73c2fbbc2a | ||
|
|
37b7e170fa | ||
|
|
b032d94877 | ||
|
|
9476016741 | ||
|
|
7a1c9c7798 | ||
|
|
c7fb7b4451 | ||
|
|
67c474fc7a | ||
|
|
4e8154cf8a | ||
|
|
9582d3c623 | ||
|
|
0079500713 | ||
|
|
55af6ce834 | ||
|
|
3e82fdc125 | ||
|
|
7344a6cfc0 | ||
|
|
0aded71343 | ||
|
|
7663b1e703 | ||
|
|
282546c03f | ||
|
|
f4bc89d1c0 | ||
|
|
fa277c3797 | ||
|
|
c0c8ab25e6 | ||
|
|
b685bf3026 | ||
|
|
ce31db09e4 | ||
|
|
624a6cf619 | ||
|
|
587aa87d28 | ||
|
|
88813c4f87 | ||
|
|
dacbe29771 | ||
|
|
244833cfa1 | ||
|
|
05e7f974e3 | ||
|
|
0dbef65a73 | ||
|
|
9106228787 | ||
|
|
6ae3bdb25c | ||
|
|
310bcec260 | ||
|
|
8c4cc4e671 | ||
|
|
c6eaaa83ed | ||
|
|
8f598d6f96 | ||
|
|
20bc323d17 | ||
|
|
8b0bcf4db9 | ||
|
|
8955e6f536 | ||
|
|
f8ddea6452 | ||
|
|
987e04086d | ||
|
|
85f2acbf52 | ||
|
|
1acf4c3ab7 | ||
|
|
07a3158fba | ||
|
|
2f8bed9d82 | ||
|
|
a490937cd9 | ||
|
|
8ee5942481 | ||
|
|
93b469885a | ||
|
|
d8d1de2dcb | ||
|
|
ab224514f0 | ||
|
|
75179de8da | ||
|
|
c28df14e6b | ||
|
|
b73855b193 | ||
|
|
2093ab2baa | ||
|
|
a0f40042cb | ||
|
|
3254c2c477 | ||
|
|
0a8eb9e3ba | ||
|
|
70e0c6f9ef | ||
|
|
a8a78d4525 | ||
|
|
57e6ee963d | ||
|
|
ce6bfb8420 | ||
|
|
f0672bdc59 | ||
|
|
23de953fbd | ||
|
|
03c496bdd8 | ||
|
|
d5ee6cf521 | ||
|
|
fb7981e053 | ||
|
|
846123ecab | ||
|
|
373cb444fe | ||
|
|
90f212df92 | ||
|
|
12286e4246 | ||
|
|
aa60c1f36a | ||
|
|
c731f01067 | ||
|
|
6c9c1cdb30 | ||
|
|
9ba2b40e87 | ||
|
|
7a3d055012 | ||
|
|
0824f45e29 | ||
|
|
4debe3446c | ||
|
|
07fe9bcdf6 | ||
|
|
6a557a73f5 | ||
|
|
8d1cfe0c56 | ||
|
|
a3a42eebea | ||
|
|
76be8006a4 | ||
|
|
bfcfd58259 | ||
|
|
914a4360e7 | ||
|
|
8c31874eeb | ||
|
|
ef7afeb2ea | ||
|
|
4067f883a2 | ||
|
|
c8974fffbe | ||
|
|
b75fb8dc9e | ||
|
|
57356781a9 | ||
|
|
e43eab5fd6 | ||
|
|
894cd0e022 | ||
|
|
db2c63fffc | ||
|
|
60e0f32f1a | ||
|
|
e731996a68 | ||
|
|
2f69cd4209 | ||
|
|
fd59de25c5 | ||
|
|
af12c3d41a | ||
|
|
54b52bbeb5 | ||
|
|
1174c68d9a | ||
|
|
448ea7167f | ||
|
|
6b27008c99 | ||
|
|
725c785882 | ||
|
|
ab068cff67 | ||
|
|
9dc03adfda | ||
|
|
49f9e4eddf | ||
|
|
43c47ac44c | ||
|
|
1cebe64664 | ||
|
|
f33c381043 | ||
|
|
3479841c77 | ||
|
|
6a899968a9 | ||
|
|
bb8405a36e | ||
|
|
c7bc711f63 | ||
|
|
e326071c35 | ||
|
|
ad6a669381 | ||
|
|
e4c9dafc9a | ||
|
|
dfc0aefd87 | ||
|
|
356b39c6f5 | ||
|
|
8da7bb6b68 | ||
|
|
9341081a4d | ||
|
|
324a086eb4 | ||
|
|
ed595f52c2 | ||
|
|
64ad0023bb | ||
|
|
fe5f661d15 | ||
|
|
ff26e3a8ba | ||
|
|
14657a762c | ||
|
|
4754fa3902 | ||
|
|
f302f87337 | ||
|
|
94dbcde292 | ||
|
|
4336a174b1 | ||
|
|
0adb13ed71 | ||
|
|
e78a3d1c19 | ||
|
|
c099ec05ee | ||
|
|
a20612478e | ||
|
|
f778e8bbd1 | ||
|
|
7203c046f9 | ||
|
|
754b61c593 | ||
|
|
927e9e4e4d | ||
|
|
699f9622d7 | ||
|
|
765eb84c33 | ||
|
|
03ba1f7021 | ||
|
|
1f7f20788c | ||
|
|
c59dd29190 | ||
|
|
99f63a41a3 | ||
|
|
a575f5df36 | ||
|
|
12a1849090 | ||
|
|
0817e627ee | ||
|
|
14d90239a7 | ||
|
|
f5d11dc656 | ||
|
|
6dcf5bf077 | ||
|
|
ac2082e9b3 | ||
|
|
dbac495bee | ||
|
|
fe5ccb163e | ||
|
|
1aea5ee007 | ||
|
|
13cd9f8067 | ||
|
|
34496ecaf0 | ||
|
|
c043b1d949 | ||
|
|
9a6d2a7b32 | ||
|
|
f8a9efa8e4 | ||
|
|
5b2169e0d1 | ||
|
|
2c927ea768 | ||
|
|
f4bbcdcbc8 | ||
|
|
79c375b1af | ||
|
|
f443a3b3a1 | ||
|
|
684d2d63f4 | ||
|
|
1900d8f843 | ||
|
|
3c2af95d21 | ||
|
|
b35414ea0f | ||
|
|
fb5b056f7b | ||
|
|
7248c1dfdb | ||
|
|
4c7ea9e893 | ||
|
|
c7801ce277 | ||
|
|
f741a8e3ff | ||
|
|
6a92e8b609 | ||
|
|
9da91a8217 | ||
|
|
69853c8e5c | ||
|
|
1f41b6c138 | ||
|
|
e001efa9fd | ||
|
|
435e64d4cf | ||
|
|
f296c8f5fb | ||
|
|
8d0e6ed32f | ||
|
|
b6a36afffe | ||
|
|
e422abc269 | ||
|
|
221d71d07b | ||
|
|
9f35f0837e | ||
|
|
515891b035 | ||
|
|
94a506876f | ||
|
|
9bde57854a | ||
|
|
f456369941 | ||
|
|
8f0a1ffe5d | ||
|
|
e4bafc621a | ||
|
|
cfa39ab3b0 | ||
|
|
47e91bfd89 | ||
|
|
eecc388ebd | ||
|
|
0a15a5ee56 | ||
|
|
cfaae47cea | ||
|
|
c1a0352592 | ||
|
|
965f45aa3f | ||
|
|
6ea27fe836 | ||
|
|
0dccc22b38 | ||
|
|
cbe833962b | ||
|
|
b5720f6f10 | ||
|
|
56b4e0b0ec | ||
|
|
e316ccb1e0 | ||
|
|
a6f93efd39 | ||
|
|
20511cf608 | ||
|
|
1a1dd39367 | ||
|
|
589981bdcb | ||
|
|
89546776b2 | ||
|
|
f0d7b3cd12 | ||
|
|
e37be627e0 | ||
|
|
d803561582 | ||
|
|
a1aab4008f | ||
|
|
a1172529bf | ||
|
|
1d905bf07f | ||
|
|
eed678a14b | ||
|
|
b1bdffbc34 | ||
|
|
cff718f37d | ||
|
|
40e9430278 | ||
|
|
62fc55fc74 | ||
|
|
80729353c8 | ||
|
|
105ba5e124 | ||
|
|
ad1b50d1f5 | ||
|
|
1905437abe | ||
|
|
87fc339c45 | ||
|
|
3af7d61d3e | ||
|
|
a45ef7a856 | ||
|
|
299998055d | ||
|
|
c9586d39ed | ||
|
|
2e9f67f4e4 | ||
|
|
e318170fea | ||
|
|
73c4289792 | ||
|
|
ea45d7ee47 | ||
|
|
6d970725e7 | ||
|
|
458c2c6d88 | ||
|
|
0cc53a8964 | ||
|
|
0bc96304a9 | ||
|
|
c75b088ff8 | ||
|
|
181f0341f5 | ||
|
|
33bb08d53b | ||
|
|
6d188f6e44 | ||
|
|
c3648331f1 | ||
|
|
a5b66029d3 | ||
|
|
49bfe80191 | ||
|
|
a5def77bfe | ||
|
|
9ecb5b4791 | ||
|
|
1cc48a370a | ||
|
|
f1ec8d1e11 | ||
|
|
55c34cd84f | ||
|
|
aca52d1e36 | ||
|
|
6f90df26a5 | ||
|
|
9d9cb378ff | ||
|
|
f92aac14aa | ||
|
|
3f27d78ab5 | ||
|
|
282d1ba22f | ||
|
|
94c19575b1 | ||
|
|
e3e485285b | ||
|
|
986e36720e | ||
|
|
74348ab6c2 | ||
|
|
8d1ad99f42 | ||
|
|
e69bbff195 | ||
|
|
c9f33bbde0 | ||
|
|
9c9f9d4fa6 | ||
|
|
2f64a6b0cb | ||
|
|
dfa78ad3c6 | ||
|
|
677ae46f0c | ||
|
|
6ada2a458f | ||
|
|
8145f3b68d | ||
|
|
48289acee6 | ||
|
|
e5a989c6f9 | ||
|
|
4c56704935 | ||
|
|
9cda44f443 | ||
|
|
431451bac2 | ||
|
|
395ca7feea | ||
|
|
e0b7533c39 | ||
|
|
5b2a402930 | ||
|
|
85129a1873 | ||
|
|
487d333024 | ||
|
|
fe7d35171f | ||
|
|
b3aed13567 | ||
|
|
a9d4d2bfa3 | ||
|
|
1ff521683f | ||
|
|
0395a03b6b | ||
|
|
7fda7709ff | ||
|
|
65a9200cff | ||
|
|
473eec26c1 | ||
|
|
9fa945ad93 | ||
|
|
a895219d2f | ||
|
|
427f7c362e | ||
|
|
73f5c41fae | ||
|
|
b4ec168401 | ||
|
|
726d35c766 | ||
|
|
6db796e10c | ||
|
|
c38d9134cd | ||
|
|
471204b163 | ||
|
|
7f23bfa66d | ||
|
|
9287b26042 | ||
|
|
e22936fbf8 | ||
|
|
04ace9fc16 | ||
|
|
8466b333fb | ||
|
|
96602612ba | ||
|
|
690b98bff9 | ||
|
|
8329131bfe | ||
|
|
9986aab326 | ||
|
|
0b105bc535 | ||
|
|
51ac9c9506 | ||
|
|
0310176696 | ||
|
|
84a7a2bc3e | ||
|
|
1e66a7e555 | ||
|
|
2bffb9d682 | ||
|
|
811125a760 | ||
|
|
0dd91082a1 | ||
|
|
c80587868e | ||
|
|
8c52dc86c7 | ||
|
|
be24592bc3 | ||
|
|
0d1a5c621d | ||
|
|
8a3eff3b65 | ||
|
|
b1050b884d | ||
|
|
181d883a1d | ||
|
|
e01b65fd3d | ||
|
|
bbd74b5ae2 | ||
|
|
d5a5c49357 | ||
|
|
a964b164a6 | ||
|
|
1aac0489d7 | ||
|
|
e474755887 | ||
|
|
bf9a60f70d | ||
|
|
a2ba0913d3 | ||
|
|
f74df41fff | ||
|
|
2a950e4ce9 | ||
|
|
f05e5f908e | ||
|
|
43139b43b1 | ||
|
|
5811b47aad | ||
|
|
54e3db4d8c | ||
|
|
7491421c31 | ||
|
|
9d0da74347 | ||
|
|
e9870b293f | ||
|
|
ab910d060b | ||
|
|
b60ef68ac6 | ||
|
|
c9986936ed | ||
|
|
d77be46644 | ||
|
|
3715d7a184 | ||
|
|
1c96c7163a | ||
|
|
9f733b25db | ||
|
|
1419a33b64 | ||
|
|
f270739f9f | ||
|
|
e51a391286 | ||
|
|
c815185574 | ||
|
|
8045e29a52 | ||
|
|
bbb3e16fd1 | ||
|
|
3cd1657387 | ||
|
|
d7ea122cf7 | ||
|
|
6aea7c7f70 | ||
|
|
56ba1d9cd3 | ||
|
|
408b03ae0d | ||
|
|
d94fd746af | ||
|
|
dbd1316d1e | ||
|
|
75845c0283 | ||
|
|
88db9751d7 | ||
|
|
6f645c4cb7 | ||
|
|
4e31d85349 | ||
|
|
de542a81c0 | ||
|
|
461576e7a2 | ||
|
|
21bd62b1ce | ||
|
|
838cd1157c | ||
|
|
2f068b91d8 | ||
|
|
aba87bf1bd | ||
|
|
e64da8ede4 | ||
|
|
a9f38dfce4 | ||
|
|
a097537a03 | ||
|
|
66e0b53cf6 | ||
|
|
06f2e81dd5 | ||
|
|
40ae2e812f | ||
|
|
06f613e40b | ||
|
|
61c8c1e8d2 | ||
|
|
ee924ee310 | ||
|
|
fad0ce3ced | ||
|
|
d396180939 | ||
|
|
0d089abe67 | ||
|
|
ed5c1dfc3c | ||
|
|
6b949a7375 | ||
|
|
3028e2908f | ||
|
|
578803b01f | ||
|
|
46738825c0 | ||
|
|
56357699cb | ||
|
|
fe8e718183 | ||
|
|
1eb34989d4 | ||
|
|
2f3b4c8bfb | ||
|
|
6412768000 | ||
|
|
82688b9a44 | ||
|
|
651e12cfe4 | ||
|
|
4118d581af | ||
|
|
62608bec03 | ||
|
|
71cffc973d | ||
|
|
a8e49d084b | ||
|
|
db631097b1 | ||
|
|
0d31674166 | ||
|
|
cb5af974a4 | ||
|
|
f2f421a0a2 | ||
|
|
413c46e2ee | ||
|
|
3b412d51f0 | ||
|
|
4931e2aee2 | ||
|
|
ffadf673cf | ||
|
|
5b5a7e5a24 | ||
|
|
ab53208f47 | ||
|
|
7c407705e8 | ||
|
|
60378ff941 | ||
|
|
30a0c77d19 | ||
|
|
07ec89276b | ||
|
|
a37dc1af9d | ||
|
|
03458df140 | ||
|
|
164eb9659e | ||
|
|
99cfbaa63b | ||
|
|
8d8a6534e3 | ||
|
|
938c5013c9 | ||
|
|
ea9d5ec793 | ||
|
|
ec65f038a8 | ||
|
|
199ec36d40 | ||
|
|
1326ded048 | ||
|
|
8347439644 | ||
|
|
cddc2a8280 | ||
|
|
97a8938407 | ||
|
|
939d1dcae9 | ||
|
|
9d5cc5c11f | ||
|
|
d998f24d26 | ||
|
|
d543f8857b | ||
|
|
c48a942d22 | ||
|
|
e1602618c3 | ||
|
|
36be240623 | ||
|
|
04e499c97f | ||
|
|
f586a8a9dc | ||
|
|
5112ed77d6 | ||
|
|
bf29a54272 | ||
|
|
6d9286a202 | ||
|
|
92fdd07ca3 | ||
|
|
1c937ad960 | ||
|
|
f9891a5c04 | ||
|
|
e8ad311d84 | ||
|
|
545c09e202 | ||
|
|
4dc281a05f | ||
|
|
3a0af8caad | ||
|
|
8ff2fecb26 | ||
|
|
1855c6aed5 | ||
|
|
d4c6643311 | ||
|
|
e8c738002b | ||
|
|
309c3aaeb8 | ||
|
|
1f8bcadb3b | ||
|
|
6f4af5fef8 | ||
|
|
868cdb9f8b | ||
|
|
2f76a429ef | ||
|
|
a69799aa42 | ||
|
|
139bef2142 | ||
|
|
8ba142bcf4 | ||
|
|
c49e4966f6 | ||
|
|
516fa4e49d | ||
|
|
6bf9f89429 | ||
|
|
a0ddfcb109 | ||
|
|
3df7921fdc | ||
|
|
6172a9ca2d | ||
|
|
4a40e57cf0 | ||
|
|
cdedda4ca1 | ||
|
|
e6babd84f7 | ||
|
|
868ec1a7e3 | ||
|
|
e08394c870 | ||
|
|
a99500aebf | ||
|
|
aa5095c23b | ||
|
|
9e0f36e5a7 | ||
|
|
d481d079ba | ||
|
|
bc9ec7ac4a | ||
|
|
6f7e81067c | ||
|
|
af946f398e | ||
|
|
c7ca26e9c7 | ||
|
|
ef7129f45d | ||
|
|
a20bdd334a | ||
|
|
2ef49a92cc | ||
|
|
75f56b68c6 | ||
|
|
d34d319d89 | ||
|
|
6660c1da38 | ||
|
|
4e263b8c39 | ||
|
|
3cb604df02 | ||
|
|
af9dc7a69e | ||
|
|
1247e69c78 | ||
|
|
aab0e4315d | ||
|
|
14f6517733 | ||
|
|
5d75effb37 | ||
|
|
ab4f18954b | ||
|
|
e1460c65e8 | ||
|
|
425a0fcf07 | ||
|
|
7205ee5e0a | ||
|
|
72c5db8910 | ||
|
|
3067f4be3a | ||
|
|
2aa1ccdd76 | ||
|
|
0284df503f | ||
|
|
2833a983d8 | ||
|
|
39c6be7cb7 | ||
|
|
fdc94c1353 | ||
|
|
9cc4e48124 | ||
|
|
34c7f15d6d | ||
|
|
899a9b025e | ||
|
|
deb4315383 | ||
|
|
9a06660fdb | ||
|
|
5c35d24e13 | ||
|
|
03f99752a7 | ||
|
|
fd37567c18 | ||
|
|
6e38bf1578 | ||
|
|
8b2d278840 | ||
|
|
06aa0a124d | ||
|
|
eb4595158d | ||
|
|
32103441f1 | ||
|
|
7ed0aa6630 | ||
|
|
f690229f31 | ||
|
|
f3bab72a86 | ||
|
|
2bd63c2d27 | ||
|
|
545d9e85e9 | ||
|
|
21a4ab4ec7 | ||
|
|
66fbbeb5ec | ||
|
|
55879c7b6d | ||
|
|
66c4e5a5e2 | ||
|
|
884139e246 | ||
|
|
c3d7b1541e | ||
|
|
51ada4d70b | ||
|
|
e3a5d52c5e | ||
|
|
559fd70737 | ||
|
|
e0dba85cbb | ||
|
|
74c9cf03d0 | ||
|
|
0774e79e4f | ||
|
|
a3ec37741a | ||
|
|
9bf5cd83c3 | ||
|
|
f0da793f99 | ||
|
|
684f3ac172 | ||
|
|
3e5bd460a5 | ||
|
|
3b1d787fbe | ||
|
|
980f55ff69 | ||
|
|
52ed68bfeb | ||
|
|
be0d4c28e4 | ||
|
|
79807bf2ab | ||
|
|
e48ca1a03f | ||
|
|
eae18ce973 | ||
|
|
591344ca9d | ||
|
|
fbe067823e | ||
|
|
ffece911e6 | ||
|
|
186afa9651 | ||
|
|
6b3037106a | ||
|
|
1bf22288ee | ||
|
|
3cec470f25 | ||
|
|
e1ec0d13ae | ||
|
|
924fe97fc3 | ||
|
|
504411eade | ||
|
|
038ca1b9ca | ||
|
|
544b192f8c | ||
|
|
7748ccdb8e | ||
|
|
64e29c6fce | ||
|
|
acdf097998 | ||
|
|
ba3107c1fa | ||
|
|
9985f787eb | ||
|
|
d6f41bcf98 | ||
|
|
50bced49ad | ||
|
|
4fd7470bbf | ||
|
|
033c6f1fdb | ||
|
|
6c58347916 | ||
|
|
cccbdc164c | ||
|
|
cea14a6869 | ||
|
|
9b4b24edf7 | ||
|
|
8b10a5fb7c | ||
|
|
b0d0d9cad2 | ||
|
|
d5c8eb048a | ||
|
|
9abee3f29a | ||
|
|
bf9b6b1301 | ||
|
|
8cd57025a0 | ||
|
|
faf60b6b1f | ||
|
|
da2c1be49c | ||
|
|
92c02449f4 | ||
|
|
e381622a9a | ||
|
|
b799223ebc | ||
|
|
40ef224a95 | ||
|
|
a4c20b6e1c | ||
|
|
e6ee867f72 | ||
|
|
468a31f515 | ||
|
|
4d746794cc | ||
|
|
02d2a66ef2 | ||
|
|
4638baf545 | ||
|
|
2be23d3768 | ||
|
|
b39b1746ba | ||
|
|
24f97510b0 | ||
|
|
325d5399fa | ||
|
|
d8f6fbf594 | ||
|
|
21b3e4052c | ||
|
|
bf2928805e | ||
|
|
7d2bf334c8 | ||
|
|
7446802a70 | ||
|
|
077bf5ebae | ||
|
|
c9bef39f96 | ||
|
|
3740eadb7d | ||
|
|
e29fa66a74 | ||
|
|
ca5406c8e4 | ||
|
|
7217caacd1 | ||
|
|
8081082251 | ||
|
|
1597ca0de5 | ||
|
|
8c938ceff9 | ||
|
|
65a6945ea5 | ||
|
|
02640812af | ||
|
|
ba761d5c35 | ||
|
|
48a3b1f07f | ||
|
|
4370cb77e7 | ||
|
|
470e8f6fc7 | ||
|
|
b270d88427 | ||
|
|
66ce247129 | ||
|
|
6ad016c587 | ||
|
|
532dac1b95 | ||
|
|
2a4bcc262f | ||
|
|
1ce2361daf | ||
|
|
6e8584e8e0 | ||
|
|
121aa91139 | ||
|
|
bbc07c72d3 | ||
|
|
43b48fdbea | ||
|
|
604f97aba1 | ||
|
|
dc980081cd | ||
|
|
981f03fef3 | ||
|
|
d40133dc72 | ||
|
|
c9fa586fce | ||
|
|
b847a7d90b | ||
|
|
8b67108dc8 | ||
|
|
b559f9625a | ||
|
|
1736c9b0f8 | ||
|
|
4fb2d8d318 | ||
|
|
95891eb0a5 | ||
|
|
c133443eb7 | ||
|
|
8f0641f36c | ||
|
|
f48dbde736 | ||
|
|
f2e4c1ae9a | ||
|
|
a4aef38cc0 | ||
|
|
b445ecde51 | ||
|
|
a209a01284 | ||
|
|
7037532943 | ||
|
|
bb405ee1aa | ||
|
|
ef23356309 | ||
|
|
1613e2593c | ||
|
|
5464a7a379 | ||
|
|
bb1331e449 | ||
|
|
acbebc5631 | ||
|
|
e1c4fc29de | ||
|
|
b903433284 | ||
|
|
31a7fdc7b6 | ||
|
|
9909adb665 | ||
|
|
26f8ba48ee | ||
|
|
29ea408980 | ||
|
|
0bb7ca7441 | ||
|
|
a992644c62 | ||
|
|
1c15926e6f | ||
|
|
c921315b3e | ||
|
|
ab740f92db | ||
|
|
1d7390fa7c | ||
|
|
0ab96b8e47 | ||
|
|
6f6edd37ef | ||
|
|
f4282de068 | ||
|
|
85c85c07b7 | ||
|
|
7abcb1579a | ||
|
|
7ce733cc16 | ||
|
|
41a3c5f846 | ||
|
|
7734e77dfc | ||
|
|
257c8b65c2 | ||
|
|
846c9e5e12 | ||
|
|
685d2b460c | ||
|
|
bd71e1cd02 | ||
|
|
43a5e12449 | ||
|
|
ca97510a52 | ||
|
|
50b753cb44 | ||
|
|
5ca6704c4d | ||
|
|
49142fa385 | ||
|
|
d631d29cb4 | ||
|
|
01b7891347 | ||
|
|
c786a4cbeb | ||
|
|
1920ecd668 | ||
|
|
c8827424e7 | ||
|
|
cc066dd6a1 | ||
|
|
eb0b37f729 | ||
|
|
e552757edc | ||
|
|
87b8dffe23 | ||
|
|
81b5904188 | ||
|
|
894a3b2fe2 | ||
|
|
b75b3e3984 | ||
|
|
dea4906144 | ||
|
|
97e5117a3f | ||
|
|
037215f7c4 | ||
|
|
0277187fde | ||
|
|
c80a3c1401 | ||
|
|
5614f85ea1 | ||
|
|
1a3c8692e6 | ||
|
|
f2e8691ad5 | ||
|
|
c94d7574bc | ||
|
|
a38cb5df18 | ||
|
|
5407868620 | ||
|
|
7edf77561b | ||
|
|
a78cbd91da | ||
|
|
bb5c3773f1 | ||
|
|
2e641a266d | ||
|
|
3a787afec6 | ||
|
|
34019222c2 | ||
|
|
5f3378213b | ||
|
|
547fda6a40 | ||
|
|
2080ac3bda | ||
|
|
61769c8f16 | ||
|
|
934e091410 | ||
|
|
7f7ee75954 | ||
|
|
e76b8da269 | ||
|
|
7e5f226480 | ||
|
|
2f634184f0 | ||
|
|
e3e01466ee | ||
|
|
025918cfcc | ||
|
|
28fb76e602 | ||
|
|
b0f97393a3 | ||
|
|
2a7041e751 | ||
|
|
58c78d0d78 | ||
|
|
eed158afdd | ||
|
|
1c7505e04a | ||
|
|
617da24942 | ||
|
|
98bdbfd3d5 | ||
|
|
b289f253c7 | ||
|
|
aabae03305 | ||
|
|
194d645551 | ||
|
|
889d6f9e43 | ||
|
|
151de093d0 | ||
|
|
cc13e45f21 | ||
|
|
7492a4c871 | ||
|
|
d20543b92c | ||
|
|
59aab2ebbd | ||
|
|
08f7b1b9e5 | ||
|
|
f2ac1c15e6 | ||
|
|
eaf8f198c1 | ||
|
|
2955286606 | ||
|
|
40561340a8 | ||
|
|
4f00a7db88 | ||
|
|
acc21d0b76 | ||
|
|
db5df70d0c | ||
|
|
a6073dc237 | ||
|
|
92c132381e | ||
|
|
d0575e4087 | ||
|
|
5ca48b96af | ||
|
|
2a9f30fc8a | ||
|
|
ba89a81a3e | ||
|
|
5f32300592 | ||
|
|
15b4d9363b | ||
|
|
ceca0e7f0e | ||
|
|
700770b883 | ||
|
|
8365037be5 | ||
|
|
dfaba7daa6 | ||
|
|
5756934144 | ||
|
|
7b3ab2727f | ||
|
|
714ba808dd | ||
|
|
6e94e03baa | ||
|
|
ac98dbccb8 | ||
|
|
6e3355d7f2 | ||
|
|
97907906c5 | ||
|
|
eb84200f28 | ||
|
|
caaa26e153 | ||
|
|
030dd747e9 | ||
|
|
dccb98bb92 | ||
|
|
e356b7141c | ||
|
|
4cae7e6d5d | ||
|
|
cc07b4a89a | ||
|
|
7e8154e648 | ||
|
|
dfee997e45 | ||
|
|
f6b7cb9c49 | ||
|
|
4452d0e0f5 | ||
|
|
7fba44ccce | ||
|
|
6f1695ecd4 | ||
|
|
76acbf9bb6 | ||
|
|
2769a62bb3 | ||
|
|
160dd830a0 | ||
|
|
aafc595e3a | ||
|
|
202783c67a | ||
|
|
f11b2c5a0d | ||
|
|
e8a86013da | ||
|
|
a89c377c92 | ||
|
|
54d73f6722 | ||
|
|
2e58f5f0d4 | ||
|
|
e7ea39f410 | ||
|
|
a125218d03 | ||
|
|
55b8563c08 | ||
|
|
aea1f59f6e | ||
|
|
ab27b789e4 | ||
|
|
3a1a59f1eb | ||
|
|
c20a76cddb | ||
|
|
1ef6db16ed | ||
|
|
230b734663 | ||
|
|
dc414f1239 | ||
|
|
dafd2329c5 | ||
|
|
12cfda1f58 | ||
|
|
96b4e71704 | ||
|
|
edb415d1a8 | ||
|
|
72c1d1c484 | ||
|
|
41a7154aa5 | ||
|
|
346d024e48 | ||
|
|
04a248dc37 | ||
|
|
5defc3b914 | ||
|
|
04ca945ecf | ||
|
|
d687db71e7 | ||
|
|
87f8fe14dd | ||
|
|
af08124229 | ||
|
|
2eadb21eb7 | ||
|
|
8b97a0dbbf | ||
|
|
69afa2a7a3 | ||
|
|
da5328bae5 | ||
|
|
a4325372e2 | ||
|
|
4b96b73858 | ||
|
|
bbae43f259 | ||
|
|
14fedbf063 | ||
|
|
ab974c409d | ||
|
|
2040709585 | ||
|
|
60214dc659 | ||
|
|
b990d77f16 | ||
|
|
d204e06e11 | ||
|
|
f6b37dbc77 | ||
|
|
fab65d6c40 | ||
|
|
ff4d49f556 | ||
|
|
dfa5fa1187 | ||
|
|
1f4f69a5b6 | ||
|
|
84f82f5465 | ||
|
|
c911f7c47e | ||
|
|
4d983e54b5 | ||
|
|
33c000daea | ||
|
|
7ff204ec44 | ||
|
|
7c757ef3bf | ||
|
|
2db7945d6f | ||
|
|
81186bf262 | ||
|
|
eeef5b0896 | ||
|
|
8189b6fc11 | ||
|
|
e5a2df93ab | ||
|
|
c3f770da27 | ||
|
|
49f66a936c | ||
|
|
83dda98240 | ||
|
|
b4ddbd0097 | ||
|
|
cbe92bb985 | ||
|
|
60c6a0d334 | ||
|
|
1baab5eb61 | ||
|
|
8fc8974b60 | ||
|
|
ecb49c2e5e | ||
|
|
29797b9eb0 | ||
|
|
e181ee586b | ||
|
|
7b7d742bec | ||
|
|
612eaff9ff | ||
|
|
d76ef187e8 | ||
|
|
e01ab86a89 | ||
|
|
89b59b4ffc | ||
|
|
e367ecf806 | ||
|
|
effc9e0f33 | ||
|
|
da06e6c6e3 | ||
|
|
c258bee54f | ||
|
|
cde4a505cf | ||
|
|
2802e66259 | ||
|
|
3a3003029a | ||
|
|
08bca8fb63 | ||
|
|
7c7ff802fa | ||
|
|
0945acc780 | ||
|
|
64ec9f9cb6 | ||
|
|
83f7de33c0 | ||
|
|
ec2d7bf349 | ||
|
|
f4c9064b79 | ||
|
|
8ede16dc26 | ||
|
|
27e400fba3 | ||
|
|
37d6cb469b | ||
|
|
100a82feb2 | ||
|
|
90e5828d5d | ||
|
|
b3e80308d4 | ||
|
|
a7abe11105 | ||
|
|
3c63a48df4 | ||
|
|
fcb88e5a98 | ||
|
|
a467b34de4 | ||
|
|
a24cc77ff8 | ||
|
|
d6675d9909 | ||
|
|
fa163093d2 | ||
|
|
e70f64e23d | ||
|
|
6f605f8141 | ||
|
|
d9419ef994 | ||
|
|
7e8639a682 | ||
|
|
452b303b4c | ||
|
|
b0f1a4967d | ||
|
|
9eb4c59c04 | ||
|
|
0d42506cde | ||
|
|
c8a13ce475 | ||
|
|
05e3467d09 | ||
|
|
90639e5068 | ||
|
|
73c7711c78 | ||
|
|
78f6b6a507 | ||
|
|
84f0ab5356 | ||
|
|
546437d799 | ||
|
|
0f05aec563 | ||
|
|
c9097623d6 | ||
|
|
6392b37c47 | ||
|
|
4fcc8075d4 | ||
|
|
b2d6a55335 | ||
|
|
1fea5f8fe7 | ||
|
|
d3e52a2afb | ||
|
|
d6ea1989cc | ||
|
|
96513665d6 | ||
|
|
b795d13f61 | ||
|
|
970f9b3981 | ||
|
|
be7dab4d17 | ||
|
|
0e44ce5cba | ||
|
|
1f8c2781dd | ||
|
|
f381a9c773 | ||
|
|
855a9a01fc | ||
|
|
a5f237993d | ||
|
|
c68264802a | ||
|
|
742469a8bc | ||
|
|
92928d5c4f | ||
|
|
8320e25d64 | ||
|
|
c16a9d8463 | ||
|
|
f1819c916a | ||
|
|
dd14b24d2a | ||
|
|
050d7c12a3 | ||
|
|
7e2c433abc | ||
|
|
6713b23a65 | ||
|
|
60078e7950 | ||
|
|
69095fbb48 | ||
|
|
c88a3c64e3 | ||
|
|
771b0d0ab1 | ||
|
|
c85310578b | ||
|
|
60e2992158 | ||
|
|
2795e8a8b7 | ||
|
|
bdf14170a4 | ||
|
|
10dcbc639a | ||
|
|
6a9bb0f4e4 | ||
|
|
c941e5a8f4 | ||
|
|
be91414c7a | ||
|
|
6839b603c8 | ||
|
|
926b68d62e | ||
|
|
d374e90033 | ||
|
|
b168b0758a | ||
|
|
54c66ecfc0 | ||
|
|
1c158bd4ff | ||
|
|
ff24143f54 | ||
|
|
dd117e81c2 | ||
|
|
f4744a18c6 | ||
|
|
259d5fabd9 | ||
|
|
d122a75efd | ||
|
|
c9ea3ac304 | ||
|
|
c63fe6ef8a | ||
|
|
72ec89dfe9 | ||
|
|
04805d106e | ||
|
|
9aed578466 | ||
|
|
77c5279296 | ||
|
|
af75bf3b64 | ||
|
|
a5157e868b | ||
|
|
01a3d8f932 | ||
|
|
f22472a644 | ||
|
|
5cac8bcf9f | ||
|
|
a2801fbef9 | ||
|
|
0b14e913da | ||
|
|
85155bb2b4 | ||
|
|
dd8de1e9ac | ||
|
|
c909835b0a | ||
|
|
a18aafedfd | ||
|
|
317ab6df6b | ||
|
|
1fcaffe6b0 | ||
|
|
3ae5c410dc | ||
|
|
381128364e | ||
|
|
0acf167e84 | ||
|
|
f7ca6deeb0 | ||
|
|
251486e4aa | ||
|
|
c6467be60d | ||
|
|
4dd512ad28 | ||
|
|
28076b9385 | ||
|
|
49dcc816ae | ||
|
|
fa61c70103 | ||
|
|
5ee6dbcdf4 | ||
|
|
634219da2c | ||
|
|
fbe3849b4b | ||
|
|
bd2e335063 | ||
|
|
96262e7d87 | ||
|
|
c5da87b860 | ||
|
|
848d4a1498 | ||
|
|
70e23df6f8 | ||
|
|
95af205681 | ||
|
|
6dfb689d1f | ||
|
|
462e74ef87 | ||
|
|
c6aa536590 | ||
|
|
c79480342b | ||
|
|
a1cc5ca045 | ||
|
|
7f74ff3dd7 | ||
|
|
c4a95e9a1e | ||
|
|
71f9e2b1d7 | ||
|
|
16fe32215b | ||
|
|
dd7342a6cf | ||
|
|
35c88d10cd | ||
|
|
42532de0eb | ||
|
|
122e2a9378 | ||
|
|
33c9395d79 | ||
|
|
fc49aa359c | ||
|
|
fcf37942a7 | ||
|
|
9b42d5a5e9 | ||
|
|
ba92dfcbe9 | ||
|
|
fd03603adb | ||
|
|
2008ddf8a8 | ||
|
|
c56b876bfe | ||
|
|
c4957d5dfb | ||
|
|
068bd33afb | ||
|
|
e9bd108be9 | ||
|
|
4f2d1cdc00 | ||
|
|
61cca10cf6 | ||
|
|
dfbdd17dce | ||
|
|
9078d3bd37 | ||
|
|
5e1a8c86f9 | ||
|
|
bf01bf631d | ||
|
|
80c5ba32b5 | ||
|
|
874cc79443 | ||
|
|
3883460202 | ||
|
|
f0dbc2e404 | ||
|
|
4df1ac5b23 | ||
|
|
1f6d0d342b | ||
|
|
4625c28e6a | ||
|
|
5536ba20a8 | ||
|
|
ef398e9036 | ||
|
|
0c73c3f1cd | ||
|
|
7ae7984f3c | ||
|
|
8286b33c52 | ||
|
|
475775cc9d | ||
|
|
11067d7a56 | ||
|
|
5b05da65f0 | ||
|
|
444e630783 | ||
|
|
8951b8de7a | ||
|
|
2abb87eb63 | ||
|
|
32e8ac912d | ||
|
|
e403fb4652 | ||
|
|
daa37c22f5 | ||
|
|
5a2a134c95 | ||
|
|
b9acb6dfa5 | ||
|
|
4e7ad3c7ce | ||
|
|
ee0e1a2342 | ||
|
|
f206b476d1 | ||
|
|
dd2595c53f | ||
|
|
545df28d71 | ||
|
|
16f80b78cf | ||
|
|
147bcce01b | ||
|
|
f5877ac6d1 | ||
|
|
adc41e31f4 | ||
|
|
2e555a930f | ||
|
|
bcba0c0279 | ||
|
|
c7f382add6 | ||
|
|
665b1e68d5 | ||
|
|
2ca9300bf7 | ||
|
|
81f62b246c | ||
|
|
87badc71d2 | ||
|
|
e5242c67ff | ||
|
|
4355420994 | ||
|
|
c357af02c2 | ||
|
|
19576effbe | ||
|
|
ecc6eb7497 | ||
|
|
d0ac318980 | ||
|
|
7b030fe70d | ||
|
|
115556fcf2 | ||
|
|
9760cf1f4e | ||
|
|
47bb7fd21b | ||
|
|
1c7ed8ca48 | ||
|
|
6b268c5df4 | ||
|
|
62f783f1dc | ||
|
|
61c65f3df1 | ||
|
|
05166b3673 | ||
|
|
0a1c93b869 | ||
|
|
788f91a36f | ||
|
|
c831ecf5d2 | ||
|
|
9e42ee153c | ||
|
|
d457aa5951 | ||
|
|
ab37ee6ebb | ||
|
|
8655530b19 | ||
|
|
27b1f59aa9 | ||
|
|
cc2cc4db43 | ||
|
|
20bcd95279 | ||
|
|
d7954be5e5 | ||
|
|
0ea77cabfb | ||
|
|
0d46352ff4 | ||
|
|
ffa0d5fe45 | ||
|
|
a2c837a99c | ||
|
|
13d8d11011 | ||
|
|
2357b6162f | ||
|
|
b4f242193d | ||
|
|
7242ee0186 | ||
|
|
3e742ffc4c | ||
|
|
2ec12fe06f | ||
|
|
c76e0ae685 | ||
|
|
25ded775ad | ||
|
|
cae4f19629 | ||
|
|
04f6c7b156 | ||
|
|
77b79e9899 | ||
|
|
a55354357c | ||
|
|
392d5d51df | ||
|
|
9bc996a630 | ||
|
|
7b709d4c68 | ||
|
|
eab5f67c5c | ||
|
|
6020106000 | ||
|
|
12f470ed10 | ||
|
|
945cbcfad6 | ||
|
|
d53007739e | ||
|
|
6eaf8272e1 | ||
|
|
6fb83dce06 | ||
|
|
52addc877d | ||
|
|
53a5f3d2dc | ||
|
|
711ee5a36d | ||
|
|
cd09b696b5 | ||
|
|
df1ca255a9 | ||
|
|
811a5d93f4 | ||
|
|
adbe361b9b | ||
|
|
0f16f21677 | ||
|
|
aa0de01e5f | ||
|
|
785757f2f6 | ||
|
|
01120dfc46 | ||
|
|
a119eb4ef0 | ||
|
|
0aa4c3d217 | ||
|
|
3c0cc59d77 | ||
|
|
7e1d095996 | ||
|
|
cfa9fb6ee4 | ||
|
|
9d23192614 | ||
|
|
7c1a52ae65 | ||
|
|
9aa1b9c740 | ||
|
|
c4a4916055 | ||
|
|
b402e0671a | ||
|
|
8144f83b66 | ||
|
|
cd2a55e268 | ||
|
|
f92b5d69c8 | ||
|
|
a8c21459c3 | ||
|
|
4789b4c9f3 | ||
|
|
ee1cd6f151 | ||
|
|
dfcda296a3 | ||
|
|
4d38fcb289 | ||
|
|
cbdea8f331 | ||
|
|
51d6a13510 | ||
|
|
7b4eeecd9f | ||
|
|
82eff7e082 | ||
|
|
b922e36071 | ||
|
|
7c75aeaad2 | ||
|
|
2db9323671 | ||
|
|
31ae93de19 | ||
|
|
a81e9f23f0 | ||
|
|
59f09a4386 | ||
|
|
53400ecac1 | ||
|
|
1b8928a8ec | ||
|
|
e706494893 | ||
|
|
894aea7ce7 | ||
|
|
87167a21c9 | ||
|
|
7c8f5ef811 | ||
|
|
7aa4241662 | ||
|
|
56a915b5b1 | ||
|
|
90a0dfa35f | ||
|
|
128d72785f | ||
|
|
21a6017547 | ||
|
|
a0964d44d5 | ||
|
|
fb0859dfe6 | ||
|
|
dadd6037bb | ||
|
|
6f3eff3258 | ||
|
|
02224d5aa9 | ||
|
|
bfd2845077 | ||
|
|
ba2e0489e6 | ||
|
|
ca7c5b8b10 | ||
|
|
6c43489fb2 | ||
|
|
d76f671d37 | ||
|
|
776ce586bc | ||
|
|
adc3066dc8 | ||
|
|
7fd2da1096 | ||
|
|
451340e4c0 | ||
|
|
a3e812b86d | ||
|
|
a3f98091c4 | ||
|
|
6720b34868 | ||
|
|
781ed0dc67 | ||
|
|
8f00848c7b | ||
|
|
53aa19a916 | ||
|
|
2dc04d2957 | ||
|
|
306bdee673 | ||
|
|
cff52ded58 | ||
|
|
fbe658a724 | ||
|
|
f9d0eb47b7 | ||
|
|
078f50d45a | ||
|
|
974a45c804 | ||
|
|
760e4e3d68 | ||
|
|
9ec5689d6b | ||
|
|
c8b72431a3 | ||
|
|
0eb913fb9a | ||
|
|
fce27cb2e8 | ||
|
|
1b6272db2e | ||
|
|
b1c0ad5e42 | ||
|
|
3f7cdcb6a7 | ||
|
|
a25b030e36 | ||
|
|
717fac02d1 | ||
|
|
dcf8ba0edb | ||
|
|
3ab2ae130b | ||
|
|
6e6900fa3a | ||
|
|
d7af4596e1 | ||
|
|
1759151875 | ||
|
|
a7ed3dea4b | ||
|
|
cdcb774dc8 | ||
|
|
d199c817dc | ||
|
|
dc51bd09f7 | ||
|
|
139e3fab25 | ||
|
|
7a98f9aa02 | ||
|
|
b53dd67e74 | ||
|
|
e546731093 | ||
|
|
d50c4ef6da | ||
|
|
7d0b1955a2 | ||
|
|
16cf7681f0 | ||
|
|
12f09ad2d7 | ||
|
|
b3e88a8d80 | ||
|
|
761273bcc4 | ||
|
|
1a75f68cb2 | ||
|
|
1b0edf54f1 | ||
|
|
caa6576719 | ||
|
|
93bd2c11fa | ||
|
|
2be09790a9 | ||
|
|
bf6eae711a | ||
|
|
69b68c0091 | ||
|
|
6f1d5d3b73 | ||
|
|
099a912992 | ||
|
|
56b1ea3726 | ||
|
|
d6391f2d70 | ||
|
|
07910272e2 | ||
|
|
1092013c2b | ||
|
|
0db83bd787 | ||
|
|
f55316eabc | ||
|
|
840f59934e | ||
|
|
75a9c59ad8 | ||
|
|
adfccd33ae | ||
|
|
9d41243c15 | ||
|
|
e33e182eb0 | ||
|
|
4dffd662f0 | ||
|
|
5064d579d4 | ||
|
|
540425a41b | ||
|
|
4d21b582c7 | ||
|
|
f288bc1790 | ||
|
|
8942e348bd | ||
|
|
9f27336827 | ||
|
|
f517cccf7b | ||
|
|
3a937ace51 | ||
|
|
b8661f8bff | ||
|
|
51828ab5f8 | ||
|
|
84fe5d7f34 | ||
|
|
2891d2b260 | ||
|
|
edfb861a5f | ||
|
|
88c1cf3ee7 | ||
|
|
813e3fdcfd | ||
|
|
bbe10e4938 | ||
|
|
cb4903fa86 | ||
|
|
ea45165db8 | ||
|
|
1fba699ed4 | ||
|
|
ce3d574c41 | ||
|
|
7a601a7eb2 | ||
|
|
9ec66ab826 | ||
|
|
ebfa07f8ce | ||
|
|
964a800d51 | ||
|
|
5c05dec65a | ||
|
|
bf6ebc4a68 | ||
|
|
2e944931b3 | ||
|
|
db67538311 | ||
|
|
307c7e00e2 | ||
|
|
45feb55483 | ||
|
|
0a1d902f46 | ||
|
|
959a577b5f | ||
|
|
b91fe8be5a | ||
|
|
d1f0a13ddc | ||
|
|
c455bdad11 | ||
|
|
bc1ef813c2 | ||
|
|
603791c0ba | ||
|
|
8091b1289f | ||
|
|
cc0035b1d7 | ||
|
|
ceba1ba4ee | ||
|
|
468e13501c | ||
|
|
32bf70571a | ||
|
|
95f4bd8e23 | ||
|
|
4c9624db64 | ||
|
|
2cbf4d8ad1 | ||
|
|
524c9b50d4 | ||
|
|
d3147b661b | ||
|
|
d3182dce51 | ||
|
|
8763df1cd0 | ||
|
|
15e05b692c | ||
|
|
2bf5e341d3 | ||
|
|
b53890ddae | ||
|
|
93602ad9ea | ||
|
|
191d0001f4 | ||
|
|
1a04ce33f1 | ||
|
|
babfe50550 | ||
|
|
ff57b3eb72 | ||
|
|
1837e89fe4 | ||
|
|
24b8b0e382 | ||
|
|
321a758ab9 | ||
|
|
1a9c14acde | ||
|
|
e8734c77b4 | ||
|
|
1eb00a9f74 | ||
|
|
922a21d359 | ||
|
|
4a4f314768 | ||
|
|
3c64596ea1 | ||
|
|
33283b1b6e | ||
|
|
2f89bdc672 | ||
|
|
2d275c4782 | ||
|
|
25156eb83e | ||
|
|
39032b45c9 | ||
|
|
821a8dca3b | ||
|
|
0145b133a1 | ||
|
|
b0b137d7f0 | ||
|
|
b0c09153c2 | ||
|
|
0485078c6c | ||
|
|
7079cc43c9 | ||
|
|
e7fca0051e | ||
|
|
6273e56886 | ||
|
|
8b9ad2dce8 | ||
|
|
301cbb0e68 | ||
|
|
5313963baf | ||
|
|
f60348eee4 | ||
|
|
a31e079f93 | ||
|
|
556edc9f0d | ||
|
|
17d0b7a985 | ||
|
|
86e00e865e | ||
|
|
5dda83dc73 | ||
|
|
28439d822a | ||
|
|
b1d8ee19ca | ||
|
|
f7c556ed8d | ||
|
|
5377e10532 | ||
|
|
30522bbf7d | ||
|
|
58374623b7 | ||
|
|
7e7498350f | ||
|
|
06c268c274 | ||
|
|
9b36e2b145 | ||
|
|
ca75f8dc20 | ||
|
|
6f2f3fdb68 | ||
|
|
c903e49a4f | ||
|
|
9121feb44f | ||
|
|
7b42ed66f2 | ||
|
|
fb26c9b2c4 | ||
|
|
78ffb63429 | ||
|
|
1213990b7d | ||
|
|
c3af30d520 | ||
|
|
2598123140 | ||
|
|
40627191f3 | ||
|
|
38dc844e85 | ||
|
|
abc4405a76 | ||
|
|
243c66442d | ||
|
|
9afcec77f6 | ||
|
|
70ad98cc6f | ||
|
|
76cfbde933 | ||
|
|
f200bd9594 | ||
|
|
4d4ca7bb36 | ||
|
|
78c3c6dafa | ||
|
|
6d859dec67 | ||
|
|
3563e7e1aa | ||
|
|
cb898fabf4 | ||
|
|
5899671d96 | ||
|
|
8c1eb23aa1 | ||
|
|
b564087db0 | ||
|
|
1748e8510e | ||
|
|
742c5bb639 | ||
|
|
297de01d95 | ||
|
|
fb31c3b46d | ||
|
|
ba2beffcd8 | ||
|
|
2eb2dddb59 | ||
|
|
0601d851d0 | ||
|
|
b731f6ab03 | ||
|
|
0403e306ed | ||
|
|
d393fbf360 | ||
|
|
4cc680965c | ||
|
|
ba08e487cb | ||
|
|
d37eda4e9b | ||
|
|
3960d0f6de | ||
|
|
5be5e5b58f | ||
|
|
04ac9b8e32 | ||
|
|
409a8a3a43 | ||
|
|
1ba3f72e4c | ||
|
|
3e5e9e57e9 | ||
|
|
02e5e49de2 | ||
|
|
43438d3824 | ||
|
|
8f82d19fd1 | ||
|
|
ee450bcd77 | ||
|
|
553b4d9428 | ||
|
|
df145f4bc9 | ||
|
|
fa55283f62 | ||
|
|
9e163db491 | ||
|
|
286230f477 | ||
|
|
3ba2c7e7e8 | ||
|
|
b4f5e5bc00 | ||
|
|
f580d2e41a | ||
|
|
cd197e8be3 | ||
|
|
51cf6465ff | ||
|
|
a1feb32a2f | ||
|
|
7478ad115f | ||
|
|
9d8e338a11 | ||
|
|
ed4163cfde | ||
|
|
bd95f742c0 | ||
|
|
463e6d9316 | ||
|
|
3358811788 | ||
|
|
a45509d28e | ||
|
|
9ba94d2c6b | ||
|
|
a4de83b3a3 | ||
|
|
68a12d1d17 | ||
|
|
c97d3cf359 | ||
|
|
4721337c7c | ||
|
|
2b36ed967c | ||
|
|
3bb8f1ac8d | ||
|
|
617ec7f565 | ||
|
|
dc259b9f8e | ||
|
|
7b31a87b3c | ||
|
|
37a430c97c | ||
|
|
f264cb0b18 | ||
|
|
6ea530cc48 | ||
|
|
a0abf307b4 | ||
|
|
55cf9f5e1c | ||
|
|
b89f0fac7b | ||
|
|
8b3b3182bd | ||
|
|
97c64f27ff | ||
|
|
e548e1f6e0 | ||
|
|
7ea1c7d85a | ||
|
|
e08235b575 | ||
|
|
783c672130 | ||
|
|
5351a6b2ed | ||
|
|
a110b103e8 | ||
|
|
c26f573620 | ||
|
|
f06e9ae30c | ||
|
|
f5d208d5d6 | ||
|
|
7fb8c4a68d | ||
|
|
647fc56d47 | ||
|
|
597d84e263 | ||
|
|
977b0c3c0c | ||
|
|
1b0d6de735 | ||
|
|
2f5bb7774e | ||
|
|
5565f02dbd | ||
|
|
17a131ac21 | ||
|
|
9a5cfe9f75 | ||
|
|
cc936d9977 | ||
|
|
e9911fee4d | ||
|
|
aefde67aa2 | ||
|
|
a1ea62a923 | ||
|
|
7209ced446 | ||
|
|
db63d352a2 | ||
|
|
289de840fd | ||
|
|
cb34a8b620 | ||
|
|
95c633914f | ||
|
|
d033412b1f | ||
|
|
9c5e97144d | ||
|
|
8b96289e2f | ||
|
|
51ff43e2f2 | ||
|
|
1e30f4f973 | ||
|
|
36f66661f7 | ||
|
|
de27fc15b6 | ||
|
|
f9f90ba1d6 | ||
|
|
51bf8a3538 | ||
|
|
7b033a48a3 | ||
|
|
1b420f69aa | ||
|
|
6a187a384b | ||
|
|
ac5de1f96e | ||
|
|
6c917f686a | ||
|
|
328ee94412 | ||
|
|
de9951594e | ||
|
|
561fc15ae9 | ||
|
|
d65814c53f | ||
|
|
803f17aa90 | ||
|
|
08a3687eb5 | ||
|
|
c4035b2273 | ||
|
|
5c364e0f7c | ||
|
|
9cfc3d9d37 | ||
|
|
b5fdd30b77 | ||
|
|
280292d3f5 | ||
|
|
c593d864be | ||
|
|
6d17348c72 | ||
|
|
536648ec19 | ||
|
|
b5e32a9ce5 | ||
|
|
4077822e37 | ||
|
|
e2d8750625 | ||
|
|
79f5751375 | ||
|
|
106437bd45 | ||
|
|
b7cd13bb0b | ||
|
|
be1ec1b973 | ||
|
|
1bddb87a0c | ||
|
|
fbe23d8c33 | ||
|
|
f435bb24ab | ||
|
|
853b33b67c | ||
|
|
19f3568e18 | ||
|
|
911c2cbe58 | ||
|
|
17bdfbb08b | ||
|
|
80f29ae859 | ||
|
|
0b114d680e | ||
|
|
c87a0910d0 | ||
|
|
b1a4f05b5a | ||
|
|
ce2079104a | ||
|
|
86e12369b6 | ||
|
|
6d096551f0 | ||
|
|
2595c8a853 | ||
|
|
2a9923999b | ||
|
|
03cbeac1ea | ||
|
|
d64e9b6263 | ||
|
|
9824a34d76 | ||
|
|
76c3436377 | ||
|
|
a4178d4b3c | ||
|
|
3e423722c6 | ||
|
|
01837f2bb6 | ||
|
|
411c5da6d3 | ||
|
|
7658ea8335 | ||
|
|
81d301a42b | ||
|
|
0b500730e0 | ||
|
|
123710078d | ||
|
|
6c08dbab0e | ||
|
|
ec0d0ba368 | ||
|
|
bed02c2f95 | ||
|
|
75bc69ba2f | ||
|
|
3f434f2a44 | ||
|
|
71d8e6b4cd | ||
|
|
a78af0a7fb | ||
|
|
eb9f74a273 | ||
|
|
117ae196fd | ||
|
|
4c211c8dce | ||
|
|
4056b94e01 | ||
|
|
ee94828355 | ||
|
|
c10d9b9d9d | ||
|
|
fff66649aa | ||
|
|
b68b0a256e | ||
|
|
b33fdc1674 | ||
|
|
6909d9c9c9 | ||
|
|
0d5d820f4f | ||
|
|
6fbca3416a | ||
|
|
466d9b31ce | ||
|
|
b6fdaaac41 | ||
|
|
c19bbfce78 | ||
|
|
e9fdbe0c89 | ||
|
|
f2299eab8f | ||
|
|
e220f44953 | ||
|
|
b750a84ab1 | ||
|
|
41f8be2c53 | ||
|
|
c3e4cbe950 | ||
|
|
50df5000c2 | ||
|
|
3c8930b72b | ||
|
|
f0572c4d5f | ||
|
|
057ba8a4e1 | ||
|
|
677737d345 | ||
|
|
930ac9c57d | ||
|
|
5caa0371c4 | ||
|
|
e6e1cb1b43 | ||
|
|
164ed0b325 | ||
|
|
8263789602 | ||
|
|
a99906c6f0 | ||
|
|
617338457d | ||
|
|
1026d2173b | ||
|
|
ca9c9ee807 | ||
|
|
bef51fe9ff | ||
|
|
b72845609f | ||
|
|
ccd8b71c4b | ||
|
|
e623690295 | ||
|
|
070baea3c4 | ||
|
|
0e828792ae | ||
|
|
31a8dfa063 | ||
|
|
338ef8f2e4 | ||
|
|
737fee94d0 | ||
|
|
4a2d770066 | ||
|
|
b7cfc08fc5 | ||
|
|
92f0e1719b | ||
|
|
9e5f203302 | ||
|
|
17cb0c1aee | ||
|
|
df32cd0aca | ||
|
|
ae5dc8c45b | ||
|
|
b1ed5b0707 | ||
|
|
eefdb3f156 | ||
|
|
e9a5cfaddd | ||
|
|
f5f2997cc2 | ||
|
|
43d2ba6275 | ||
|
|
8b98b331cc | ||
|
|
e0130e7fd7 | ||
|
|
fb491f0d7c | ||
|
|
33b5d9651f | ||
|
|
9109e369ff | ||
|
|
b97e011715 | ||
|
|
1bb9a9368b | ||
|
|
ca3dac7e87 | ||
|
|
59302d4f42 | ||
|
|
fabb722c8d | ||
|
|
657fae490c | ||
|
|
e9acebe0e8 | ||
|
|
7a84fc4742 | ||
|
|
4be3d66a32 | ||
|
|
92df01b99d | ||
|
|
5c9c738913 | ||
|
|
83c357d9d1 | ||
|
|
3bb3adefbb | ||
|
|
cf670153f9 | ||
|
|
d6cd69e659 | ||
|
|
48d31ad7bc | ||
|
|
20aa258f0e | ||
|
|
45a60956a6 | ||
|
|
4ae372262b | ||
|
|
02167a15d1 | ||
|
|
b50a4669d2 | ||
|
|
c947bda604 | ||
|
|
00451777fe | ||
|
|
a65386e925 | ||
|
|
2d7d154ffc | ||
|
|
3100080a50 | ||
|
|
7275370ae5 | ||
|
|
e013381e72 | ||
|
|
d05bb1c125 | ||
|
|
273d1ff2d0 | ||
|
|
235605bfa4 | ||
|
|
e8b3587946 | ||
|
|
9040ac6a0c | ||
|
|
a73ba56ebb | ||
|
|
1168f47768 | ||
|
|
73dba691b1 | ||
|
|
b1f76139a7 | ||
|
|
6b986fecb0 | ||
|
|
535ab8302b | ||
|
|
7125b3430c | ||
|
|
0615d09b7a | ||
|
|
1add0c7d43 | ||
|
|
8194f5ccaf | ||
|
|
057486cf56 | ||
|
|
f94e726271 | ||
|
|
95660002e1 | ||
|
|
95c669389b | ||
|
|
084fc9776d | ||
|
|
1498fdb7b0 | ||
|
|
79c3139748 | ||
|
|
bdd64f5656 | ||
|
|
dc3e9fb77c | ||
|
|
4b417c0e9d | ||
|
|
06c28f3a4d | ||
|
|
688fe6db5e | ||
|
|
9aefb59afe | ||
|
|
e3862b86b5 | ||
|
|
125cd222bb | ||
|
|
a0f351c9fa | ||
|
|
f7b49a2c91 | ||
|
|
fd70b47768 | ||
|
|
5d1fd390a6 | ||
|
|
8b5663e385 | ||
|
|
8b5bcaee3c | ||
|
|
ca845aa256 | ||
|
|
761ea65d81 | ||
|
|
1dc32d5e3d | ||
|
|
1c0a015cc8 | ||
|
|
bee415217d | ||
|
|
73989f5cc7 | ||
|
|
dd458c8ab5 | ||
|
|
63e9790123 | ||
|
|
70e1f3ac81 | ||
|
|
67f1872f4a | ||
|
|
8bbb7907d6 | ||
|
|
c98e1f3cae | ||
|
|
6b0f93ce8a | ||
|
|
80f19a0ab7 | ||
|
|
41894eb285 | ||
|
|
3535efd977 | ||
|
|
f6bd41ada7 | ||
|
|
7b5f40772f | ||
|
|
d2ebf4b52d | ||
|
|
0fe5c672a6 | ||
|
|
ce7d51f9be | ||
|
|
cc1f84d1d3 | ||
|
|
74126d9f24 | ||
|
|
69eb9531da | ||
|
|
da4d8254fa | ||
|
|
57332c5ccf | ||
|
|
9bc5ac05c4 | ||
|
|
0a4d58468e | ||
|
|
8ce092da68 | ||
|
|
fce1529bf2 | ||
|
|
61edf22a45 | ||
|
|
84974d6c56 | ||
|
|
da438a93e0 | ||
|
|
a87015598c | ||
|
|
c335bf5dc5 | ||
|
|
c6a782c0ce | ||
|
|
d148e14aa2 | ||
|
|
748a5d41c1 | ||
|
|
c876e63010 | ||
|
|
23b811243f | ||
|
|
99d9c57154 | ||
|
|
13559baecc | ||
|
|
481647ed5d | ||
|
|
5c162ce588 | ||
|
|
e1b6175efd | ||
|
|
ea46f096c2 | ||
|
|
da88dd8cfa | ||
|
|
9b5c6112e5 | ||
|
|
ea1341a129 | ||
|
|
343cb779d2 | ||
|
|
b0af01a762 | ||
|
|
d8617514f8 | ||
|
|
e579d1d89f | ||
|
|
63812c9f80 | ||
|
|
676a0afe4c | ||
|
|
42c257d0fc | ||
|
|
d5e5c98dc8 | ||
|
|
12d21dcb85 | ||
|
|
5054eb4276 | ||
|
|
122c77dbf6 | ||
|
|
3c66cab4e7 | ||
|
|
738fd479b3 | ||
|
|
5c612095a1 | ||
|
|
3e60e82529 | ||
|
|
60f8dd0bfc | ||
|
|
2a7008a82c | ||
|
|
0d3c6abee8 | ||
|
|
4a693222b4 | ||
|
|
82e052f2ec | ||
|
|
0745c15d7b | ||
|
|
2904c19ed9 | ||
|
|
16fe0a301c | ||
|
|
aebb8010d4 | ||
|
|
4ac382e553 | ||
|
|
596111c988 | ||
|
|
e202d30835 | ||
|
|
fbe903b277 | ||
|
|
8a89e50c13 | ||
|
|
6cb0e0dcea | ||
|
|
a147ea3e80 | ||
|
|
557988e530 | ||
|
|
67fb2c212f | ||
|
|
3765b08cca | ||
|
|
3eb84fcb13 | ||
|
|
bea76e8e08 | ||
|
|
f5433dcaa4 | ||
|
|
ef3b953a42 | ||
|
|
605a205008 | ||
|
|
058f63b440 | ||
|
|
71882475d6 | ||
|
|
a3d29a15df | ||
|
|
a09112404d | ||
|
|
93fc11ea21 | ||
|
|
4faa129b8e | ||
|
|
6c4ed0409d | ||
|
|
ea2811f14f | ||
|
|
8bc2987a71 | ||
|
|
1d13095d19 | ||
|
|
5ed76f197a | ||
|
|
e1f4cadf41 | ||
|
|
3b0e6357ad | ||
|
|
02f17bd4e4 | ||
|
|
b63a0796fd | ||
|
|
e6d4e729fb | ||
|
|
b75a22b753 | ||
|
|
72beeeeaaa | ||
|
|
c3c42ef56f | ||
|
|
a3c55681b2 | ||
|
|
cc70388846 | ||
|
|
fcc610f539 | ||
|
|
5bbd507858 | ||
|
|
45156c0c47 | ||
|
|
553e38ffd6 | ||
|
|
c4ca0490ee | ||
|
|
b145d47863 | ||
|
|
095827a261 | ||
|
|
87ecdb8112 | ||
|
|
98b2fa4d64 | ||
|
|
810ef7401c | ||
|
|
ae70a03383 | ||
|
|
081d132538 | ||
|
|
bb5c478704 | ||
|
|
ff6601f29e | ||
|
|
320c6c6f05 | ||
|
|
6b89da4bb2 | ||
|
|
5b82b9e101 | ||
|
|
1d0e862129 | ||
|
|
f089b2001f | ||
|
|
9f8420bf50 | ||
|
|
8275da63fb | ||
|
|
72696600d8 | ||
|
|
1aeb317863 | ||
|
|
b49b510732 | ||
|
|
a0d61e45d5 | ||
|
|
95f1ef7561 | ||
|
|
edb2fab64c | ||
|
|
464fb73d83 | ||
|
|
6a4e63a17d | ||
|
|
168f94d29a | ||
|
|
3c2b1baff2 | ||
|
|
f2815d7068 | ||
|
|
f48d9465f5 | ||
|
|
6b1d5c6d7b | ||
|
|
789ef3608b | ||
|
|
57b08a57a0 | ||
|
|
5b6b9f1597 | ||
|
|
47f246ba66 | ||
|
|
b6b70d54ef | ||
|
|
417d9a14cc | ||
|
|
244566ccd4 | ||
|
|
ca4a35c90a | ||
|
|
e4ea8bc867 | ||
|
|
5d840b944b | ||
|
|
1e28876494 | ||
|
|
a40b2767c5 | ||
|
|
279b536646 | ||
|
|
ff163a5ae4 | ||
|
|
65379741f7 | ||
|
|
3eb0927a2b | ||
|
|
a3a45511e5 | ||
|
|
a20ea702e2 | ||
|
|
d2d0300c7e | ||
|
|
6e8aac984f | ||
|
|
6721c70b9e | ||
|
|
b8c1c1c144 | ||
|
|
e380c01dd1 | ||
|
|
655633ef34 | ||
|
|
3d1de237f6 | ||
|
|
6a63b13d69 | ||
|
|
3aca5502dc | ||
|
|
665f4bf248 | ||
|
|
b76ff3bdfc | ||
|
|
00450cd9db | ||
|
|
c344a543b0 | ||
|
|
554202f6e8 | ||
|
|
7590cfc610 | ||
|
|
eee8338064 | ||
|
|
3b5183a74e | ||
|
|
3ee43c3abb | ||
|
|
efdb13f0c7 | ||
|
|
f013c6e48d | ||
|
|
6e67899401 | ||
|
|
381dd1ce98 | ||
|
|
b0d8369534 | ||
|
|
4a7b18d841 | ||
|
|
7c4ffe9b9a | ||
|
|
de4f8f9aaf | ||
|
|
6554cc4a8d | ||
|
|
fac47e8ecb | ||
|
|
7443305039 | ||
|
|
635ae3a523 | ||
|
|
4a05b4556e | ||
|
|
c074615550 | ||
|
|
bac2b74b3d | ||
|
|
a3aaa6634d | ||
|
|
6a3a983f43 | ||
|
|
7996edfef9 | ||
|
|
0600b32908 | ||
|
|
77343e02e9 | ||
|
|
a3d4ecddba | ||
|
|
65403ec9fe | ||
|
|
3d3d314fb7 | ||
|
|
90b3730a0a | ||
|
|
3f3b756b61 | ||
|
|
d3b9b8d452 | ||
|
|
390c042027 | ||
|
|
c864828735 | ||
|
|
e0c9910d85 | ||
|
|
e62f12426b | ||
|
|
d3af50e4cc | ||
|
|
cbdb700edf | ||
|
|
6010b95fca | ||
|
|
e351dde651 | ||
|
|
714bd61d56 | ||
|
|
f9e9c70b6c | ||
|
|
6123c41f13 | ||
|
|
1aaa5618de | ||
|
|
16202216b2 | ||
|
|
8f1527712e | ||
|
|
fbe8998ca8 | ||
|
|
47e8f669f5 | ||
|
|
d804ee3c07 | ||
|
|
06a78d90d9 | ||
|
|
bc2ebce086 | ||
|
|
a07de921d0 | ||
|
|
6bc67b70a6 | ||
|
|
f06addfe06 | ||
|
|
7c2c50ee16 | ||
|
|
8580d3c27e | ||
|
|
951e10f272 | ||
|
|
2349ea9405 | ||
|
|
b17bf259f7 | ||
|
|
6b093bdcca | ||
|
|
10ec319c32 | ||
|
|
8cb63cebbe | ||
|
|
7d26de6697 | ||
|
|
8262290bff | ||
|
|
2779037f13 | ||
|
|
734c85d7ef | ||
|
|
05bd5767de | ||
|
|
59d288c429 | ||
|
|
8c41c0b6a7 | ||
|
|
f5f3858da1 | ||
|
|
738490e674 | ||
|
|
6a13703e32 | ||
|
|
20d5d560f3 | ||
|
|
aaabca6fc7 | ||
|
|
4b440618d6 | ||
|
|
01a79dc965 | ||
|
|
0df220780a | ||
|
|
a360cb7922 | ||
|
|
b9a2bb8104 | ||
|
|
f4a46ba6ea | ||
|
|
79bb9e54d5 | ||
|
|
135aff9e17 | ||
|
|
8ae6ae65a1 | ||
|
|
f4d7fd97f6 | ||
|
|
031a9894b0 | ||
|
|
fcc09d7ea9 | ||
|
|
7f1f684b21 | ||
|
|
d8d482e433 | ||
|
|
3fdc053d6c | ||
|
|
8be3ce18aa | ||
|
|
eda61455d3 | ||
|
|
00107c092c | ||
|
|
c5907258c3 | ||
|
|
64e1961193 | ||
|
|
f7ee8bd30d | ||
|
|
c0d2140d14 | ||
|
|
1bdde9c4f7 | ||
|
|
333ae7c4f8 | ||
|
|
f7b7c83264 | ||
|
|
6f9c9879ca | ||
|
|
b8df47e063 | ||
|
|
9dad8bf56d | ||
|
|
689f2dcbb4 | ||
|
|
163e2a5b22 | ||
|
|
e36334e14b | ||
|
|
60304c7e27 | ||
|
|
28d41039b8 | ||
|
|
b8d530da36 | ||
|
|
4fad0714e7 | ||
|
|
ca17eb4a2b | ||
|
|
4fe005e3c3 | ||
|
|
2f9ed8a572 | ||
|
|
688e18a891 | ||
|
|
8162c64ca3 | ||
|
|
e179f26d50 | ||
|
|
8db68c04c4 | ||
|
|
7c92c64730 | ||
|
|
01c6ffe1d5 | ||
|
|
46f57f5c38 | ||
|
|
1ec2e08f21 | ||
|
|
77742dec11 | ||
|
|
3cb947b37e | ||
|
|
62cf407f0c | ||
|
|
bbed72f39f | ||
|
|
99c94a78d6 | ||
|
|
2dd852da54 | ||
|
|
3c87d89df3 | ||
|
|
f4ad627b54 | ||
|
|
68a5667a1a | ||
|
|
693c6d63d4 | ||
|
|
f18c3323ea | ||
|
|
f74e19e673 | ||
|
|
da70807292 | ||
|
|
9f8bc6bb8a | ||
|
|
64b9482602 | ||
|
|
8fbcae6029 | ||
|
|
064475cb8d | ||
|
|
f4077b678a | ||
|
|
51678c1aba | ||
|
|
17a2fdbf1b | ||
|
|
65d7c3eed1 | ||
|
|
41bb8c543b | ||
|
|
bbd7355313 | ||
|
|
772916593b | ||
|
|
9d8af7355f | ||
|
|
521a29446f | ||
|
|
a8e4c4bed0 | ||
|
|
6471b4d100 | ||
|
|
7f9b2b34d1 | ||
|
|
789c5f135a | ||
|
|
344f0b743d | ||
|
|
d8841de180 | ||
|
|
23c7c3bf1c | ||
|
|
3d117804dd | ||
|
|
77bb0ebe3f | ||
|
|
6d9e51e4be | ||
|
|
174ff87946 | ||
|
|
ea02b2fde9 | ||
|
|
962cd7e5f5 | ||
|
|
65be9ae095 | ||
|
|
bc2bac8cd3 | ||
|
|
b567ece401 | ||
|
|
f001b0a40c | ||
|
|
04579664fd | ||
|
|
f709d7eb40 | ||
|
|
2df8660f8b | ||
|
|
a68ee7aac6 | ||
|
|
f0e04e734c | ||
|
|
0e7cf51890 | ||
|
|
b54d9725d8 | ||
|
|
2f0570aad6 | ||
|
|
3d40c95e80 | ||
|
|
ed5027db5d | ||
|
|
c4047f3f88 | ||
|
|
ec1a06cfaf | ||
|
|
17e47a798c | ||
|
|
212aceedc6 | ||
|
|
e6f897f4ef | ||
|
|
6c7f376410 | ||
|
|
e93e237c67 | ||
|
|
a1cd759759 | ||
|
|
a2c45a697b | ||
|
|
acdbf8911c | ||
|
|
9269372768 | ||
|
|
5575e7577a | ||
|
|
ef02dacdb4 | ||
|
|
c6b639b939 | ||
|
|
0b0fb18c42 | ||
|
|
b872ee024f | ||
|
|
a15d841b5b | ||
|
|
bfb638cfc2 | ||
|
|
3a47ad5d99 | ||
|
|
e3c88295f2 | ||
|
|
75bb8fbcd1 | ||
|
|
9cb25ad7b1 | ||
|
|
f361830cb2 | ||
|
|
9dd152dc28 | ||
|
|
2ba4337e6f | ||
|
|
48fcd927ab | ||
|
|
407d8af026 | ||
|
|
d0570b55b1 | ||
|
|
a964a95c1e | ||
|
|
c2f8441572 | ||
|
|
099a957e6c | ||
|
|
a2e515ab89 | ||
|
|
2bebace8eb | ||
|
|
5142722da3 | ||
|
|
52dd0f132a | ||
|
|
022be217a2 | ||
|
|
5528bca7a9 | ||
|
|
ae474bc8d0 | ||
|
|
ddc4274314 | ||
|
|
da93a73dbd | ||
|
|
31f8778aa3 | ||
|
|
0ecd74d01d | ||
|
|
bd20b16a32 | ||
|
|
933f4b9111 | ||
|
|
3492ed6d88 | ||
|
|
e28262f5ab | ||
|
|
94246f7574 | ||
|
|
07b0ef1648 | ||
|
|
6a39c4b91d | ||
|
|
b9f0f14e31 | ||
|
|
4238379552 | ||
|
|
8cc43ad2d1 | ||
|
|
94b472df64 | ||
|
|
2b2c1ff917 | ||
|
|
c7912249b2 | ||
|
|
b8004555ea | ||
|
|
58ff7f0788 | ||
|
|
f1afc5b0b4 | ||
|
|
bc8ee207d5 | ||
|
|
76342540dc | ||
|
|
56784a34a1 | ||
|
|
eca42e98f6 | ||
|
|
c3f1b54171 | ||
|
|
9b7d642c38 | ||
|
|
f24e2f8706 | ||
|
|
aa7f3411f5 | ||
|
|
5b9eda5e87 | ||
|
|
7c2ae45809 | ||
|
|
36b2f27873 | ||
|
|
b8e02afd1a | ||
|
|
0fc36aa5d0 | ||
|
|
38f7e256d0 | ||
|
|
4187c972a3 | ||
|
|
2d5af32660 | ||
|
|
e592b24333 | ||
|
|
8700a407ce | ||
|
|
8ecf359bbe | ||
|
|
eb1988a5ae | ||
|
|
5b6dffe93d | ||
|
|
1a6eb52f11 | ||
|
|
57ccfb692c | ||
|
|
eb1c21b0da | ||
|
|
66d82c4513 | ||
|
|
c9c4424261 | ||
|
|
131733549d | ||
|
|
ee646dadf2 | ||
|
|
73f5314141 | ||
|
|
4c5734c2ee | ||
|
|
546669082f | ||
|
|
4a0ee5df7d | ||
|
|
4de6c2ad61 | ||
|
|
1fa7e73c58 | ||
|
|
0e690b4fa0 | ||
|
|
c804ae9f7c | ||
|
|
dbcceefc20 | ||
|
|
1a4035b02c | ||
|
|
e908029392 | ||
|
|
fd4220f254 | ||
|
|
de6c3d6d70 | ||
|
|
77cb823719 | ||
|
|
49954c7a30 | ||
|
|
11a7a7069a | ||
|
|
2487162ccf | ||
|
|
8ca10f37bd | ||
|
|
4199c42fe2 | ||
|
|
f39cf702db | ||
|
|
db9e431bf7 | ||
|
|
328454729e | ||
|
|
73a4c395d2 | ||
|
|
70328437f1 | ||
|
|
600bed9f6d | ||
|
|
55eca44c54 | ||
|
|
0ac5b243c7 | ||
|
|
9911c90b1d | ||
|
|
a1f35e21c7 | ||
|
|
9ccdab0bc7 | ||
|
|
a20e956f6d | ||
|
|
59668133a2 | ||
|
|
73db8584e0 | ||
|
|
cecc7e6b9d | ||
|
|
3a14aad615 | ||
|
|
8368e55151 | ||
|
|
ac85fca8a1 | ||
|
|
e5fbe5c557 | ||
|
|
474bcd50a1 | ||
|
|
70c8b6838d | ||
|
|
212479188a | ||
|
|
5b1e59b535 | ||
|
|
779d788efa | ||
|
|
6233d804c8 | ||
|
|
8f31a53276 | ||
|
|
6a763aac95 | ||
|
|
5cd6580c2d | ||
|
|
81a2af700a | ||
|
|
8a58be81ba | ||
|
|
fc53445d08 | ||
|
|
db261aabf4 | ||
|
|
36ef1c4749 | ||
|
|
5ae520a2c9 | ||
|
|
8e31bda8f6 | ||
|
|
474aed8cfe | ||
|
|
0509376aea | ||
|
|
570f04ca05 | ||
|
|
ded08b6e1e | ||
|
|
f3c0d9115f | ||
|
|
bf609445c1 | ||
|
|
13ef2bd905 | ||
|
|
4e4cdb6356 | ||
|
|
688d297a18 | ||
|
|
9e1c3e0f41 | ||
|
|
4acc63e325 | ||
|
|
967a8b5a70 | ||
|
|
92b7d91697 | ||
|
|
07db4c530e | ||
|
|
a3fb2d6e0a | ||
|
|
5b9e37e2cc | ||
|
|
88f28773da | ||
|
|
66e6979812 | ||
|
|
8a91c52fa2 | ||
|
|
e542ba7e4d | ||
|
|
bca0392738 | ||
|
|
74d51ab08b | ||
|
|
6bc400eb8c | ||
|
|
7df0ec6aed | ||
|
|
a0a980e0ef | ||
|
|
6988fd3cab | ||
|
|
c3273e8751 | ||
|
|
d37c43716a | ||
|
|
1bf751367b | ||
|
|
976dfc7195 | ||
|
|
8372d1e499 | ||
|
|
e65716f6ee | ||
|
|
4b24d77b2c | ||
|
|
02fc4ae27b | ||
|
|
624f5f428e | ||
|
|
5171dfd2a8 | ||
|
|
8ff5e49d1f | ||
|
|
134163708a | ||
|
|
40e6616df0 | ||
|
|
bcd2089f71 | ||
|
|
7553b277db | ||
|
|
d71cf093bb | ||
|
|
86d21816b6 | ||
|
|
c9521e093e | ||
|
|
16f6261b44 | ||
|
|
6b76ac3d18 | ||
|
|
5681e02e0f | ||
|
|
41a22f258e | ||
|
|
0d2844b7c9 | ||
|
|
719f7ba0c4 | ||
|
|
44ed2c6b47 | ||
|
|
c9292ef648 | ||
|
|
135abff100 | ||
|
|
7252db1e63 | ||
|
|
05e3fd3cc6 | ||
|
|
6f1b03b67e | ||
|
|
dca247f01d | ||
|
|
63e7ca4623 | ||
|
|
75d21d9f45 | ||
|
|
8911daaf6c | ||
|
|
1f55d40a10 | ||
|
|
6591e7636d | ||
|
|
c12eaa926a | ||
|
|
0e464ded3d | ||
|
|
aee1687215 | ||
|
|
58e3e63a89 | ||
|
|
9b605b27bd | ||
|
|
c5010dffb4 | ||
|
|
026f26f05f | ||
|
|
cf2d3861d6 | ||
|
|
6ceaf9d28d | ||
|
|
25a9804d91 | ||
|
|
cf19cd5292 | ||
|
|
03824dd9f7 | ||
|
|
280dca3998 | ||
|
|
46e09e4c71 | ||
|
|
427b2638e0 | ||
|
|
2541806dc1 | ||
|
|
0d16b9e1a1 | ||
|
|
b2263ed5b5 | ||
|
|
45c2819068 | ||
|
|
d28925fdab | ||
|
|
9097e36ea0 | ||
|
|
99ef4c7510 | ||
|
|
b9e05d06fe | ||
|
|
423b6db855 | ||
|
|
bb54b940c0 | ||
|
|
4149df1fca | ||
|
|
8dd8af742a | ||
|
|
d47804d222 | ||
|
|
8dd322c0be | ||
|
|
7fd0748c19 | ||
|
|
655d4b3aad | ||
|
|
5f51476526 | ||
|
|
d47b5f8c6a | ||
|
|
a18a251d16 | ||
|
|
8ee54e887f | ||
|
|
088c926196 | ||
|
|
54b66a4199 | ||
|
|
f9d57103f4 | ||
|
|
f780df0aa6 | ||
|
|
fede40f279 | ||
|
|
6ae5a9be60 | ||
|
|
e9f3dc7d5c | ||
|
|
841b58042f | ||
|
|
63e3e02a39 | ||
|
|
944347e828 | ||
|
|
7910a5feef | ||
|
|
2becd196dd | ||
|
|
bcb45157a8 | ||
|
|
70ffe3b6bd | ||
|
|
339dea9390 | ||
|
|
b26a7bb22a | ||
|
|
45dfc7cc96 | ||
|
|
9d020c3ec5 | ||
|
|
8cda06b995 | ||
|
|
a8afc5b81f | ||
|
|
228d045a06 | ||
|
|
c447e7b3a5 | ||
|
|
803c3fc235 | ||
|
|
a032529437 | ||
|
|
7bee204390 | ||
|
|
064a700edd | ||
|
|
7809f89dfc | ||
|
|
940860755c | ||
|
|
1b283c47b4 | ||
|
|
8e427317cd | ||
|
|
908a3b6f5c | ||
|
|
f2ba91899f | ||
|
|
16127fc55c | ||
|
|
97d874f16b | ||
|
|
8aba5e76ae | ||
|
|
0e7144f2dc | ||
|
|
9f48c3e2db | ||
|
|
e6306ea188 | ||
|
|
0e99d8d80f | ||
|
|
de5cd73cd7 | ||
|
|
b585d19519 | ||
|
|
8753d2dcb8 | ||
|
|
39f1d81fd4 | ||
|
|
fcd203c646 | ||
|
|
4ebb749131 | ||
|
|
37a943d9b5 | ||
|
|
2f2b875c2a | ||
|
|
99f147219a | ||
|
|
7a13d24e6f | ||
|
|
8dc91755f7 | ||
|
|
96a3104fe2 | ||
|
|
97f525d069 | ||
|
|
4ad1bdec15 | ||
|
|
530d94a4b9 | ||
|
|
141d3e9588 | ||
|
|
98eaadf2d1 | ||
|
|
54a04b5894 | ||
|
|
8bc8709d0e | ||
|
|
730080e6fd | ||
|
|
d4b49cd622 | ||
|
|
7e0586cb55 | ||
|
|
05695a35c7 | ||
|
|
58ffb9d7a5 | ||
|
|
7eb487d998 | ||
|
|
f903ee8acc | ||
|
|
91cbe2e22c | ||
|
|
c45bad9437 | ||
|
|
4aa6afbf47 | ||
|
|
29054e8072 | ||
|
|
060d11e4c2 | ||
|
|
77870508de | ||
|
|
133ad0d355 | ||
|
|
711fe64a51 | ||
|
|
78b5c94cb0 | ||
|
|
95266bdcf8 | ||
|
|
b78879dc18 | ||
|
|
5d29079393 | ||
|
|
b052a57fc8 | ||
|
|
292be33b9d | ||
|
|
0360942942 | ||
|
|
c35d6d2396 | ||
|
|
1c73d8ce2b | ||
|
|
6a539df480 | ||
|
|
1de09ec149 | ||
|
|
a1f785038d | ||
|
|
5d475848a6 | ||
|
|
2695f2da46 | ||
|
|
3cdbf5753d | ||
|
|
daf92be5bc | ||
|
|
79bbb0ee1c | ||
|
|
826bb1abbe | ||
|
|
81789a6930 | ||
|
|
28fb2403d9 | ||
|
|
1872bd344f | ||
|
|
54170d92db | ||
|
|
ec62e871dd | ||
|
|
4ba912cd57 | ||
|
|
7713674ff6 | ||
|
|
0fce440455 | ||
|
|
ab782d8896 | ||
|
|
c84ddefc53 | ||
|
|
5802155882 | ||
|
|
ee8a68f7b2 | ||
|
|
61bbeebfba | ||
|
|
18da183ef7 | ||
|
|
19c6714f06 | ||
|
|
2193193b12 | ||
|
|
850a2d7f79 | ||
|
|
ca5dce5d9f | ||
|
|
40eff3e4a3 | ||
|
|
d334f070a3 | ||
|
|
44e752d737 | ||
|
|
5c83ebd75d | ||
|
|
02ce3031e9 | ||
|
|
2b295a5459 | ||
|
|
6caf8d3d56 | ||
|
|
b18f1e8127 | ||
|
|
3e67916971 | ||
|
|
21cccc00d7 | ||
|
|
4809867b33 | ||
|
|
8bbe518696 | ||
|
|
17b4dc1fc6 | ||
|
|
cca19e921e | ||
|
|
de50a38bb1 | ||
|
|
c2ef58d880 | ||
|
|
eafcb548ce | ||
|
|
ec32d11b76 | ||
|
|
7e97687c9e | ||
|
|
da5a64131f | ||
|
|
71e5278364 | ||
|
|
d6a1faa380 | ||
|
|
166862ecff | ||
|
|
3c133bd677 | ||
|
|
b0b1024f8a | ||
|
|
cc07ff987d | ||
|
|
efc38b87de | ||
|
|
a3a3e4c0dc | ||
|
|
d46bcd5b8f | ||
|
|
dfe00fee94 | ||
|
|
9118f2ce08 | ||
|
|
a0e98b9aa8 | ||
|
|
0d3986abbb | ||
|
|
529b34d84e | ||
|
|
e0fe8476aa | ||
|
|
0ca0180f27 | ||
|
|
21a355c89f | ||
|
|
e528b86a2a | ||
|
|
2e6ee39506 | ||
|
|
894877a0e3 | ||
|
|
6887dd05f6 | ||
|
|
95dbad6ec1 | ||
|
|
ea88ae1a5b | ||
|
|
e8e4d637ef | ||
|
|
3928136670 | ||
|
|
0dcae6c3d6 | ||
|
|
b639ccdad1 | ||
|
|
affcb5b459 | ||
|
|
70c80d7899 | ||
|
|
fb7914a3c8 | ||
|
|
6099d2a45d | ||
|
|
044fc7c461 | ||
|
|
7c4670c3de | ||
|
|
c1113d61d6 | ||
|
|
2c4366dd71 | ||
|
|
d66f8333c1 | ||
|
|
1588359ebc | ||
|
|
a861399ecb | ||
|
|
a7f3d3436f | ||
|
|
75f1bb6a7c | ||
|
|
0384b83c31 | ||
|
|
c68361a03f | ||
|
|
0bda455cad | ||
|
|
bb7bef7188 | ||
|
|
b8032ec61d | ||
|
|
8d1e6ddffc | ||
|
|
f7f2f5e84f | ||
|
|
bedd9ccaa1 | ||
|
|
a29e717fd7 | ||
|
|
522545287e | ||
|
|
4b4fe80404 | ||
|
|
cf05ff610f | ||
|
|
300124961f | ||
|
|
7eb78c8028 | ||
|
|
1a7691dade | ||
|
|
3b51501847 | ||
|
|
fc46030e7d | ||
|
|
ff3bb66272 | ||
|
|
1ceaceada4 | ||
|
|
19a0444f41 | ||
|
|
0102a72538 | ||
|
|
9943bdd907 | ||
|
|
264c5bc02b | ||
|
|
9ba8728176 | ||
|
|
8839731951 | ||
|
|
e88a9af2f6 | ||
|
|
a5e50a0f65 | ||
|
|
7c35acca75 | ||
|
|
4bb57550c8 | ||
|
|
446ab037b0 | ||
|
|
4adfb9f2d3 | ||
|
|
9c89d1c658 | ||
|
|
3598f056bb | ||
|
|
779fcf2d54 | ||
|
|
3bbc121c6a | ||
|
|
82edc19137 | ||
|
|
5689ef1af1 | ||
|
|
b4e25e5597 | ||
|
|
647139cdf9 | ||
|
|
6225f8d334 | ||
|
|
95eb54045f | ||
|
|
43520ac67d | ||
|
|
802a2d6b71 | ||
|
|
d9a4ef05ac | ||
|
|
f00a2770ef | ||
|
|
b83fe146fa | ||
|
|
6249f03367 | ||
|
|
bfc00b67bd | ||
|
|
2b7428ed2b | ||
|
|
64a80c57e3 | ||
|
|
efb2ab06cb | ||
|
|
b082c8123e | ||
|
|
cc1ff9125a | ||
|
|
5734e02034 | ||
|
|
6e8beff0a0 | ||
|
|
c21eaa5474 | ||
|
|
13667292c6 | ||
|
|
22eb8372dd | ||
|
|
1b7a9def25 | ||
|
|
d7954e6fe3 | ||
|
|
c20c9cd5d7 | ||
|
|
46531d9a60 | ||
|
|
d9a366fbed | ||
|
|
64bf52372a | ||
|
|
0a9715a94c | ||
|
|
c82aac1365 | ||
|
|
e697cc3811 | ||
|
|
c150f2f2c1 | ||
|
|
0a54e1ed62 | ||
|
|
b9daf41327 | ||
|
|
2d2bc436e6 | ||
|
|
3d76d988c3 | ||
|
|
bea6dbbf3d | ||
|
|
e1bd24c2ab | ||
|
|
1f30ea66e9 | ||
|
|
c43aaf8986 | ||
|
|
2acc81d1c5 | ||
|
|
26513a7a16 | ||
|
|
d005ac6888 | ||
|
|
7fdb098a20 | ||
|
|
a4a200e037 | ||
|
|
15d95d8803 | ||
|
|
46950a8cb3 | ||
|
|
4867cab569 | ||
|
|
c8cf7c2445 | ||
|
|
1b63215aad | ||
|
|
bcbe42ab23 | ||
|
|
c8c6419013 | ||
|
|
e8516c29e0 | ||
|
|
12247bd958 | ||
|
|
9d30d5f6e3 | ||
|
|
ba0956488d | ||
|
|
31f502b508 | ||
|
|
efaaead378 | ||
|
|
4d47d92a4a | ||
|
|
b39ad97a87 | ||
|
|
af23040d9c | ||
|
|
fd2d706e33 | ||
|
|
178d175bcf | ||
|
|
7a7f586094 | ||
|
|
5124587c96 | ||
|
|
6c897b1a37 | ||
|
|
c6ac53f4be | ||
|
|
2d7812a06c | ||
|
|
db55277b58 | ||
|
|
75818217a6 | ||
|
|
486b80fa7b | ||
|
|
873054d055 | ||
|
|
f12f896020 | ||
|
|
09ab391d13 | ||
|
|
7569930b0c | ||
|
|
e7189438dd | ||
|
|
3c304ddc35 | ||
|
|
1696de233c | ||
|
|
ce9cd4fcef | ||
|
|
698e89aba4 | ||
|
|
4c8dd4b96c | ||
|
|
11998b3913 | ||
|
|
840610facf | ||
|
|
0280deccae | ||
|
|
4d5a95784a | ||
|
|
b43d93cf55 | ||
|
|
3f137ed0b1 | ||
|
|
5deb13d73e | ||
|
|
82a1c8635e | ||
|
|
010e2e4652 | ||
|
|
ddedae6831 | ||
|
|
6c63c4f129 | ||
|
|
802686e3df | ||
|
|
3be79e8735 | ||
|
|
a303704a7d | ||
|
|
b5e6c0b8fc | ||
|
|
98c46fcfb1 | ||
|
|
409da697dd | ||
|
|
91c3685705 | ||
|
|
411fc77ecf | ||
|
|
0378ba78cc | ||
|
|
55d8e8b56b | ||
|
|
97ad4c4f89 | ||
|
|
8de999c8f7 | ||
|
|
f444bd25ef | ||
|
|
43c0db4b0e | ||
|
|
8f168c600d | ||
|
|
ec43afb426 | ||
|
|
880049c0ee | ||
|
|
2b7ac16784 | ||
|
|
56d903d75b | ||
|
|
7054e878fb | ||
|
|
dde5351d11 | ||
|
|
7d49e3e6f1 | ||
|
|
30cb01e2f0 | ||
|
|
018e836ef5 | ||
|
|
7b25125431 | ||
|
|
0aa2f68793 | ||
|
|
516e031f67 | ||
|
|
3331f2fa02 | ||
|
|
dd1a199ebd | ||
|
|
f35b5765d6 | ||
|
|
8359044408 | ||
|
|
9f3dde3cc7 | ||
|
|
ad0f7d9b0d | ||
|
|
f647ac5631 | ||
|
|
e4c5eb4c76 | ||
|
|
dc9fc9c3f5 | ||
|
|
3b6a51df24 | ||
|
|
f2313b9959 | ||
|
|
805b3bbb88 | ||
|
|
232ea22dc5 | ||
|
|
3388acd2db | ||
|
|
52ab9fb475 | ||
|
|
c7dc3611bc | ||
|
|
7a313f6038 | ||
|
|
bbcfaf1289 | ||
|
|
bfb0cb331e | ||
|
|
1759252071 | ||
|
|
fff60b053b | ||
|
|
65ac17986a | ||
|
|
ff720f1320 | ||
|
|
5a28d8d1fa | ||
|
|
ea25766374 | ||
|
|
88b8418253 | ||
|
|
4fa1b28cad | ||
|
|
c70d59edee | ||
|
|
5694998382 | ||
|
|
1cfc7b3b0d | ||
|
|
03e3ecb0a1 | ||
|
|
f8935b0692 | ||
|
|
702b50b7a1 | ||
|
|
e7baa2ae3d | ||
|
|
bfb354b469 | ||
|
|
3c0f12ea4d | ||
|
|
25a93ac4a6 | ||
|
|
0bad523913 | ||
|
|
5b36199aea | ||
|
|
a474a640be | ||
|
|
f10028d41a | ||
|
|
eb4684a64d | ||
|
|
73b81e0253 | ||
|
|
027f106a56 | ||
|
|
20e94adb61 | ||
|
|
9100794cea | ||
|
|
4ddf90e301 | ||
|
|
d1eca1cf52 | ||
|
|
7918add47d | ||
|
|
513d551df6 | ||
|
|
ddaa5e34e6 | ||
|
|
208eb7520a | ||
|
|
2d7df6b78e | ||
|
|
7527142549 | ||
|
|
4e6193b67e | ||
|
|
4ded5e10a2 | ||
|
|
1596511175 | ||
|
|
d514eab627 | ||
|
|
5287007cd6 | ||
|
|
e5a56174e2 | ||
|
|
6c68c7a35f | ||
|
|
675c1030fd | ||
|
|
ed65d04b81 | ||
|
|
fa1c5c85b5 | ||
|
|
59c69e6896 | ||
|
|
ee35786c8f | ||
|
|
ec6e2cfd62 | ||
|
|
7d48e7fd1f | ||
|
|
0063e3a69d | ||
|
|
cd6c009c03 | ||
|
|
b15cf193a0 | ||
|
|
429dc70374 | ||
|
|
e50e77e5f9 | ||
|
|
2fdd6aa0f7 | ||
|
|
cc55364b21 | ||
|
|
71526d1d9b | ||
|
|
e239980da7 | ||
|
|
1709bce77e | ||
|
|
d6ba2de888 | ||
|
|
61c0a4bc87 | ||
|
|
8af28d3fa5 | ||
|
|
970923d0e5 | ||
|
|
5d7dc0a57c | ||
|
|
c5090606a4 | ||
|
|
bf2d9ae634 | ||
|
|
871a58e1db | ||
|
|
53c7f2eedd | ||
|
|
bfd3845218 | ||
|
|
22d75d017f | ||
|
|
37e6ea0a23 | ||
|
|
10769f6f2e | ||
|
|
082639319e | ||
|
|
f20ad34c76 | ||
|
|
c045eadefa | ||
|
|
e2337b2ec4 | ||
|
|
90c5d12613 | ||
|
|
6016662807 | ||
|
|
2c9195b507 | ||
|
|
b47c48b59a | ||
|
|
98758b68ab | ||
|
|
7f1b5d4d70 | ||
|
|
25aa7a26c5 | ||
|
|
cb2caecbb3 | ||
|
|
1e299632e4 | ||
|
|
94a2084723 | ||
|
|
22e24fb47b | ||
|
|
93f0d5f626 | ||
|
|
bad040665f | ||
|
|
a07d76b264 | ||
|
|
1db6d0e0bc | ||
|
|
34849ea7b3 | ||
|
|
5a9f7c3a85 | ||
|
|
15c6300608 | ||
|
|
c6a4485623 | ||
|
|
090c6ac975 | ||
|
|
319575c864 | ||
|
|
42a0af3b1b | ||
|
|
9bc899ccf2 | ||
|
|
d29e3a1199 | ||
|
|
41bb6a9833 | ||
|
|
95e54c66b6 | ||
|
|
31e2415bbb | ||
|
|
2a5234b390 | ||
|
|
ad5b0a371e | ||
|
|
ba4dd9b5bb | ||
|
|
d42bdf2443 | ||
|
|
a246877c1e | ||
|
|
98e68a5cb4 | ||
|
|
e12aace02c | ||
|
|
51a9c7104d | ||
|
|
75dc08ff21 | ||
|
|
6fa60820a3 | ||
|
|
609a9621af | ||
|
|
8ba1121161 | ||
|
|
9a080197e7 | ||
|
|
e65375277a | ||
|
|
4a111b38b1 | ||
|
|
a363dce943 | ||
|
|
687a3c91f5 | ||
|
|
951aa0d8cd | ||
|
|
a61b59be87 | ||
|
|
91f3c17a5b | ||
|
|
0382dc976b | ||
|
|
69dcab2b55 | ||
|
|
c4f6f1d256 | ||
|
|
b57e530553 | ||
|
|
021b71ad62 | ||
|
|
0ee2ff1b05 | ||
|
|
adaa014d7c | ||
|
|
dc9dc98e80 | ||
|
|
4a2d4f52b5 | ||
|
|
8d37e544ab | ||
|
|
b07adce2b9 | ||
|
|
624be87c97 | ||
|
|
1b9591b5e3 | ||
|
|
a4cc23971f | ||
|
|
9ed1c35d30 | ||
|
|
6158ec0ce5 | ||
|
|
009bed158b | ||
|
|
402dc2a767 | ||
|
|
b5eb888af6 | ||
|
|
172261b89f | ||
|
|
8cc2c964c1 | ||
|
|
efbb704247 | ||
|
|
7fef5be3af | ||
|
|
1753f8bc18 | ||
|
|
235019ec39 | ||
|
|
7d17159ae4 | ||
|
|
56d7d4ef39 | ||
|
|
77c379faa8 | ||
|
|
3014a59c3e | ||
|
|
d70049dbb1 | ||
|
|
4713219317 | ||
|
|
36f92db61e | ||
|
|
59393fc73b | ||
|
|
3eb44f1f79 | ||
|
|
fb5119bf43 | ||
|
|
febfefa4b2 | ||
|
|
632b920e97 | ||
|
|
c81bf42f6b | ||
|
|
4147c0ce1f | ||
|
|
602e30a421 | ||
|
|
92a5567b4a | ||
|
|
9495be328c | ||
|
|
0eae75a5c2 | ||
|
|
8e0d7f2539 | ||
|
|
9c1c7fb384 | ||
|
|
af48912f11 | ||
|
|
327d2ed849 | ||
|
|
db64a682be | ||
|
|
4d3c655058 | ||
|
|
2becebce92 | ||
|
|
0cc6c6ff33 | ||
|
|
115bc6140b | ||
|
|
b14fcb068b | ||
|
|
2ea28f29b0 | ||
|
|
7cb1c7cef2 | ||
|
|
9d60e8b343 | ||
|
|
340a6c4d8d | ||
|
|
e5a4c6fc2b | ||
|
|
db9ac6dba5 | ||
|
|
d570aae817 | ||
|
|
59e4b15fad | ||
|
|
b3401381fa | ||
|
|
beed839d12 | ||
|
|
f4908ebc41 | ||
|
|
1147482e62 | ||
|
|
4d07176f1c | ||
|
|
8c67bf82f6 | ||
|
|
0823eb7327 | ||
|
|
8cff3dd2c3 | ||
|
|
df550efb6b | ||
|
|
00a47dc0cb | ||
|
|
811b1825cb | ||
|
|
2ca252bc0e | ||
|
|
6054858359 | ||
|
|
1d50fd9485 | ||
|
|
a982f351d7 | ||
|
|
27a274b686 | ||
|
|
cb002e7b84 | ||
|
|
c022a1cf1a | ||
|
|
9d4effc02e | ||
|
|
7c19ed8a48 | ||
|
|
ef5f80ad38 | ||
|
|
dbcbb4466d | ||
|
|
7927078b49 | ||
|
|
b61c9eb991 | ||
|
|
ed72dcf82d | ||
|
|
9480ad24cc | ||
|
|
a9574b692f | ||
|
|
8d9a88e759 | ||
|
|
732de8f88d | ||
|
|
6af5800d21 | ||
|
|
540b326c54 | ||
|
|
660a2b41ae | ||
|
|
d2d502b9ae | ||
|
|
3aae524964 | ||
|
|
07912f5ab2 | ||
|
|
ffc14f6019 | ||
|
|
1e70c97ef0 | ||
|
|
54227ebff1 | ||
|
|
33087fe9de | ||
|
|
6d5ff43de7 | ||
|
|
c715912ea3 | ||
|
|
3b6ff3c09a | ||
|
|
efab484fff | ||
|
|
4ba7fbb8bb | ||
|
|
53cc7ebd29 | ||
|
|
c6f032340a | ||
|
|
0ce5acec89 | ||
|
|
44e31cac5d | ||
|
|
029394db31 | ||
|
|
00020ba8ab | ||
|
|
1f91ee30fe | ||
|
|
0f0c415bcf | ||
|
|
a6f022a73d | ||
|
|
ec02d55145 | ||
|
|
cb1a773ca8 | ||
|
|
0dc1217d69 | ||
|
|
06f38d3380 | ||
|
|
2e1ec3700d | ||
|
|
9e6b1d1b16 | ||
|
|
bdf03b4706 | ||
|
|
4d96ba3ba9 | ||
|
|
f161002390 | ||
|
|
eb576d6caf | ||
|
|
e0d26629e0 | ||
|
|
17783c3c3e | ||
|
|
c64e92a5de | ||
|
|
291c13bafc | ||
|
|
c6672e62ac | ||
|
|
eb9bd38256 | ||
|
|
3ac6b2335a | ||
|
|
c6edf03ae8 | ||
|
|
5020a1bae9 | ||
|
|
86ba69c16b | ||
|
|
5f70024f87 | ||
|
|
9ff819a4a1 | ||
|
|
1244e2e93b | ||
|
|
8ab60e475a |
@@ -1,11 +0,0 @@
|
||||
image: freebsd
|
||||
packages:
|
||||
- gmake
|
||||
- gcc
|
||||
sources:
|
||||
- https://github.com/janet-lang/janet.git
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake CC=gcc
|
||||
gmake test CC=gcc
|
||||
11
.builds/freebsd.yml
Normal file
11
.builds/freebsd.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
image: freebsd/12.x
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
sudo gmake install
|
||||
21
.builds/linux.yml
Normal file
21
.builds/linux.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
image: archlinux
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- meson
|
||||
tasks:
|
||||
- with-epoll: |
|
||||
cd janet
|
||||
meson setup with-epoll --buildtype=release
|
||||
cd with-epoll
|
||||
meson configure -Depoll=true
|
||||
ninja
|
||||
ninja test
|
||||
- no-epoll: |
|
||||
cd janet
|
||||
meson setup no-epoll --buildtype=release
|
||||
cd no-epoll
|
||||
meson configure -Depoll=false
|
||||
ninja
|
||||
ninja test
|
||||
sudo ninja install
|
||||
32
.builds/openbsd.yml
Normal file
32
.builds/openbsd.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
image: openbsd/latest
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
- meson
|
||||
tasks:
|
||||
- gmake: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
doas gmake install
|
||||
gmake test-install
|
||||
- meson_min: |
|
||||
cd janet
|
||||
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false
|
||||
cd build_meson_min
|
||||
ninja
|
||||
- meson_prf: |
|
||||
cd janet
|
||||
meson setup build_meson_prf --buildtype=release -Dprf=true
|
||||
cd build_meson_prf
|
||||
ninja
|
||||
ninja test
|
||||
- meson_default: |
|
||||
cd janet
|
||||
meson setup build_meson_default --buildtype=release
|
||||
cd build_meson_default
|
||||
ninja
|
||||
ninja test
|
||||
doas ninja install
|
||||
|
||||
11
.gitattributes
vendored
11
.gitattributes
vendored
@@ -1,2 +1,9 @@
|
||||
# Use an approximate language for syntax highlighting (clojure is pretty close)
|
||||
*.janet linguist-language=clojure
|
||||
*.janet linguist-language=Janet
|
||||
*.janet text eol=lf
|
||||
*.c text eol=lf
|
||||
*.h text eol=lf
|
||||
*.md text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.build text eol=lf
|
||||
*.txt text eol=lf
|
||||
*.sh text eol=lf
|
||||
|
||||
41
.github/workflows/codeql.yml
vendored
Normal file
41
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: "2 7 * * 4"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ cpp ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
||||
62
.github/workflows/release.yml
vendored
Normal file
62
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
|
||||
release:
|
||||
permissions:
|
||||
contents: write # for softprops/action-gh-release to create GitHub release
|
||||
name: Build release binaries
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, macos-latest ]
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Set the version
|
||||
run: echo "version=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
|
||||
- name: Set the platform
|
||||
run: echo "platform=$(tr '[A-Z]' '[a-z]' <<< $RUNNER_OS)" >> $GITHUB_ENV
|
||||
- name: Compile the project
|
||||
run: make clean && make
|
||||
- name: Build the artifact
|
||||
run: JANET_DIST_DIR=janet-${{ env.version }}-${{ env.platform }} make build/janet-${{ env.version }}-${{ env.platform }}-x64.tar.gz
|
||||
- name: Draft the release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
build/*.gz
|
||||
build/janet.h
|
||||
build/c/janet.c
|
||||
build/c/shell.c
|
||||
|
||||
release-windows:
|
||||
permissions:
|
||||
contents: write # for softprops/action-gh-release to create GitHub release
|
||||
name: Build release binaries for windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Setup MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Build the project
|
||||
shell: cmd
|
||||
run: build_win all
|
||||
- name: Draft the release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
./dist/*.zip
|
||||
./*.zip
|
||||
./*.msi
|
||||
91
.github/workflows/test.yml
vendored
Normal file
91
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
|
||||
test-posix:
|
||||
name: Build and test on POSIX systems
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, macos-latest ]
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Compile the project
|
||||
run: make clean && make
|
||||
- name: Test the project
|
||||
run: make test
|
||||
|
||||
test-windows:
|
||||
name: Build and test on Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Setup MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Build the project
|
||||
shell: cmd
|
||||
run: build_win
|
||||
- name: Test the project
|
||||
shell: cmd
|
||||
run: build_win test
|
||||
|
||||
test-mingw:
|
||||
name: Build on Windows with Mingw (no test yet)
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Setup Mingw
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: UCRT64
|
||||
update: true
|
||||
install: >-
|
||||
base-devel
|
||||
git
|
||||
gcc
|
||||
- name: Build the project
|
||||
shell: cmd
|
||||
run: make -j CC=gcc
|
||||
|
||||
test-mingw-linux:
|
||||
name: Build and test with Mingw on Linux + Wine
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Setup Mingw and wine
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install libstdc++6:i386 libgcc-s1:i386
|
||||
sudo apt-get install gcc-mingw-w64-x86-64-win32 wine wine32 wine64
|
||||
- name: Compile the project
|
||||
run: make clean && make CC=x86_64-w64-mingw32-gcc LD=x86_64-w64-mingw32-gcc UNAME=MINGW RUN=wine
|
||||
- name: Test the project
|
||||
run: make test UNAME=MINGW RUN=wine
|
||||
|
||||
test-arm-linux:
|
||||
name: Build and test ARM32 cross compilation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Setup qemu and cross compiler
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-arm-linux-gnueabi qemu-user
|
||||
- name: Compile the project
|
||||
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" CC=arm-linux-gnueabi-gcc LD=arm-linux-gnueabi-gcc
|
||||
- name: Test the project
|
||||
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" SUBRUN="qemu-arm -L /usr/arm-linux-gnueabi/" test
|
||||
34
.gitignore
vendored
34
.gitignore
vendored
@@ -4,6 +4,7 @@ dst
|
||||
janet
|
||||
!*/**/janet
|
||||
/build
|
||||
/builddir
|
||||
/Build
|
||||
/Release
|
||||
/Debug
|
||||
@@ -12,9 +13,30 @@ janet
|
||||
janet-*.tar.gz
|
||||
dist
|
||||
|
||||
# jpm lockfile
|
||||
lockfile.janet
|
||||
|
||||
# Kakoune (fzf via fd)
|
||||
.fdignore
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.cproject
|
||||
|
||||
# Gnome Builder
|
||||
.buildconfig
|
||||
|
||||
# Local directory for testing
|
||||
local
|
||||
|
||||
# Common test files I use.
|
||||
temp.janet
|
||||
temp*.janet
|
||||
scratch.janet
|
||||
|
||||
# Emscripten
|
||||
*.bc
|
||||
janet.js
|
||||
@@ -26,6 +48,7 @@ janet.wasm
|
||||
|
||||
# Generate test files
|
||||
*.out
|
||||
.orig
|
||||
|
||||
# Tools
|
||||
xxd
|
||||
@@ -33,6 +56,7 @@ xxd.exe
|
||||
|
||||
# VSCode
|
||||
.vs
|
||||
.clangd
|
||||
|
||||
# Swap files
|
||||
*.swp
|
||||
@@ -44,6 +68,13 @@ tags
|
||||
vgcore.*
|
||||
*.out.*
|
||||
|
||||
# WiX artifacts
|
||||
*.msi
|
||||
*.wixpdb
|
||||
|
||||
# Makefile config
|
||||
/config.mk
|
||||
|
||||
# Created by https://www.gitignore.io/api/c
|
||||
|
||||
### C ###
|
||||
@@ -114,3 +145,6 @@ compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
|
||||
# End of https://www.gitignore.io/api/cmake
|
||||
|
||||
# Astyle
|
||||
*.orig
|
||||
|
||||
23
.travis.yml
23
.travis.yml
@@ -1,23 +0,0 @@
|
||||
language: c
|
||||
script:
|
||||
- make
|
||||
- make test
|
||||
- make build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
before_deploy:
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: JSqAOTH1jmfVlbOuPO3BbY1BhPq+ddiBNPCxuAyKHoVwfO4eNAmq9COI+UwCMWY3dg+YlspufRwkHj//B7QQ6hPbSsKu+Mapu6gr/CAE/jxbfO/E98LkIkUwbGjplwtzw2kiBkHN/Bu6J5X76cwo4D8nwQ1JIcV3nWtoG87t7H4W0R4AYQkbLGAPylgUFr11YMPx2cRBBqCdLAGIrny7kQ/0cRBfkN81R/gUJv/q3OjmUvY7sALXp7mFdZb75QPSilKIDuVUU5hLvPYTeRl6cWI/M+m5SmGZx1rjv5S9Qaw070XoNyt9JAADtbOUnADKvDguDZIP1FCuT1Gb+cnJPzrvk6+OBU9s8UjCTFtgV+LKlhmRZcwV5YQBE94PKRMJNC6VvIWM7UeQ8Zhm1jmQS6ONNWbuoUAlkZP57NtDQa2x0GT2wkubNSQKlaY+6/gwTD9KAJIzaZG7HYXH7b+4g7VbccCyhDAtDZtXgrOIS4WAkNc8rWezRO4H0qHMyON9aCEb0eTE8hWIufbx6ymG4gUxnYO+AkrEYMCwQvU6lS8BsevkaMTVtSShqlQtJ9FRlmJA3MA2ONyqzQXJENqRydyVbpFrKSv+0HbMyhEc5BoKbt0QcTh/slouNV4eASNar/GKN7aP8XKGUeMwIoCcRpP+3ehmwX9SUw7Ah5S42pA=
|
||||
file: build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
draft: true
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
repo: janet-lang/janet
|
||||
condition: "$CC = clang"
|
||||
802
CHANGELOG.md
802
CHANGELOG.md
@@ -1,7 +1,805 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 0.4.0 - ??
|
||||
## Unreleased - ???
|
||||
- Add new string escape sequences `\\a`, `\\b`, `\\?`, and `\\'`.
|
||||
- Fix bug with marshalling channels
|
||||
- Add `div` for floored division
|
||||
- Make `div` and `mod` variadic
|
||||
- Support `bnot` for integer types.
|
||||
- Define `(mod x 0)` as `x`
|
||||
- Add `ffi/pointer-cfunction` to convert pointers to cfunctions
|
||||
|
||||
## 1.29.1 - 2023-06-19
|
||||
- Add support for passing booleans to PEGs for "always" and "never" matching.
|
||||
- Allow dictionary types for `take` and `drop`
|
||||
- Fix bug with closing channels while other fibers were waiting on them - `ev/take`, `ev/give`, and `ev/select` will now return the correct (documented) value when another fiber closes the channel.
|
||||
- Add `ffi/calling-conventions` to show all available calling conventions for FFI.
|
||||
- Add `net/setsockopt`
|
||||
- Add `signal` argument to `os/proc-kill` to send signals besides `SIGKILL` on Posix.
|
||||
- Add `source` argument to `os/clock` to get different time sources.
|
||||
- Various combinator functions now are variadic like `map`
|
||||
- Add `file/lines` to iterate over lines in a file lazily.
|
||||
- Reorganize test suite to be sorted by module rather than pseudo-randomly.
|
||||
- Add `*task-id*`
|
||||
- Add `env` argument to `fiber/new`.
|
||||
- Add `JANET_NO_AMALG` flag to Makefile to properly incremental builds
|
||||
- Optimize bytecode compiler to generate fewer instructions and improve loops.
|
||||
- Fix bug with `ev/gather` and hung fibers.
|
||||
- Add `os/isatty`
|
||||
- Add `has-key?` and `has-value?`
|
||||
- Make imperative arithmetic macros variadic
|
||||
- `ev/connect` now yields to the event loop instead of blocking while waiting for an ACK.
|
||||
|
||||
## 1.28.0 - 2023-05-13
|
||||
- Various bug fixes
|
||||
- Make nested short-fn's behave a bit more predictably (it is still not recommended to nest short-fns).
|
||||
- Add `os/strftime` for date formatting.
|
||||
- Fix `ev/select` on threaded channels sometimes live-locking.
|
||||
- Support the `NO_COLOR` environment variable to turn off VT100 color codes in repl (and in scripts).
|
||||
See http://no-color.org/
|
||||
- Disallow using `(splice x)` in contexts where it doesn't make sense rather than silently coercing to `x`.
|
||||
Instead, raise a compiler error.
|
||||
- Change the names of `:user8` and `:user9` sigals to `:interrupt` and `:await`
|
||||
- Change the names of `:user8` and `:user9` fiber statuses to `:interrupted` and `:suspended`.
|
||||
- Add `ev/all-tasks` to see all currently suspended fibers.
|
||||
- Add `keep-syntax` and `keep-syntax!` functions to make writing macros easier.
|
||||
|
||||
## 1.27.0 - 2023-03-05
|
||||
- Change semantics around bracket tuples to no longer be equal to regular tuples.
|
||||
- Add `index` argument to `ffi/write` for symmetry with `ffi/read`.
|
||||
- Add `buffer/push-at`
|
||||
- Add `ffi/pointer-buffer` to convert pointers to buffers the cannot be reallocated. This
|
||||
allows easier manipulation of FFI memory, memory mapped files, and buffer memory shared between threads.
|
||||
- Calling `ev/cancel` on a fiber waiting on `ev/gather` will correctly
|
||||
cancel the child fibers.
|
||||
- Add `(sandbox ...)` function to core for permission based security. Also add `janet_sandbox` to C API.
|
||||
The sandbox allows limiting access to the file system, network, ffi, and OS resources at runtime.
|
||||
- Add `(.locals)` function to debugger to see currently bound local symbols.
|
||||
- Track symbol -> slot mapping so debugger can get symbolic information. This exposes local bindings
|
||||
in `debug/stack` and `disasm`.
|
||||
- Add `os/compiler` to detect what host compiler was used to compile the interpreter
|
||||
- Add support for mingw and cygwin builds (mingw support also added in jpm).
|
||||
|
||||
## 1.26.0 - 2023-01-07
|
||||
- Add `ffi/malloc` and `ffi/free`. Useful as tools of last resort.
|
||||
- Add `ffi/jitfn` to allow calling function pointers generated at runtime from machine code.
|
||||
Bring your own assembler, though.
|
||||
- Channels can now be marshalled. Pending state is not saved, only items in the channel.
|
||||
- Use the new `.length` function pointer on abstract types for lengths. Adding
|
||||
a `length` method will still work as well.
|
||||
- Support byte views on abstract types with the `.bytes` function pointer.
|
||||
- Add the `u` format specifier to printf family functions.
|
||||
- Allow printing 64 integer types in `printf` and `string/format` family functions.
|
||||
- Allow importing modules from custom directories more easily with the `@` prefix
|
||||
to module paths. For example, if there is a dynamic binding :custom-modules that
|
||||
is a file system path to a directory of modules, import from that directory with
|
||||
`(import @custom-modules/mymod)`.
|
||||
- Fix error message bug in FFI library.
|
||||
|
||||
## 1.25.1 - 2022-10-29
|
||||
- Add `memcmp` function to core library.
|
||||
- Fix bug in `os/open` with `:rw` permissions not correct on Linux.
|
||||
- Support config.mk for more easily configuring the Makefile.
|
||||
|
||||
## 1.25.0 - 2022-10-10
|
||||
- Windows FFI fixes.
|
||||
- Fix PEG `if-not` combinator with captures in the condition
|
||||
- Fix bug with `os/date` with nil first argument
|
||||
- Fix bug with `net/accept` on Linux that could leak file descriptors to subprocesses
|
||||
- Reduce number of hash collisions from pointer hashing
|
||||
- Add optional parameter to `marshal` to skip cycle checking code
|
||||
|
||||
## 1.24.1 - 2022-08-24
|
||||
- Fix FFI bug on Linux/Posix
|
||||
- Improve parse error messages for bad delimiters.
|
||||
- Add optional `name` parameter to the `short-fn` macro.
|
||||
|
||||
## 1.24.0 - 2022-08-14
|
||||
- Add FFI support to 64-bit windows compiled with MSVC
|
||||
- Don't process shared object names passed to dlopen.
|
||||
- Add better support for windows console in the default shell.c for auto-completion and
|
||||
other shell-like input features.
|
||||
- Improve default error message from `assert`.
|
||||
- Add the `tabseq` macro for simpler table comprehensions.
|
||||
- Allow setting `(dyn :task-id)` in fibers to improve context in supervisor messages. Prior to
|
||||
this change, supervisor messages over threaded channels would be from ambiguous threads/fibers.
|
||||
|
||||
## 1.23.0 - 2022-06-20
|
||||
- Add experimental `ffi/` module for interfacing with dynamic libraries and raw function pointers. Only available
|
||||
on 64 bit linux, mac, and bsd systems.
|
||||
- Allow using `&named` in function prototypes for named arguments. This is a more ergonomic
|
||||
variant of `&keys` that isn't as redundant, more self documenting, and allows extension to
|
||||
things like default arguments.
|
||||
- Add `delay` macro for lazy evaluate-and-save thunks.
|
||||
- Remove pthread.h from janet.h for easier includes.
|
||||
- Add `debugger` - an easy to use debugger function that just takes a fiber.
|
||||
- `dofile` will now start a debugger on errors if the environment it is passed has `:debug` set.
|
||||
- Add `debugger-on-status` function, which can be passed to `run-context` to start a debugger on
|
||||
abnormal fiber signals.
|
||||
- Allow running scripts with the `-d` flag to use the built-in debugger on errors and breakpoints.
|
||||
- Add mutexes (locks) and reader-writer locks to ev module for thread coordination.
|
||||
- Add `parse-all` as a generalization of the `parse` function.
|
||||
- Add `os/cpu-count` to get the number of available processors on a machine
|
||||
|
||||
## 1.22.0 - 2022-05-09
|
||||
- Prohibit negative size argument to `table/new`.
|
||||
- Add `module/value`.
|
||||
- Remove `file/popen`. Use `os/spawn` with the `:pipe` options instead.
|
||||
- Fix bug in peg `thru` and `to` combinators.
|
||||
- Fix printing issue in `doc` macro.
|
||||
- Numerous updates to function docstrings
|
||||
- Add `defdyn` aliases for various dynamic bindings used in core.
|
||||
- Install `janet.h` symlink to make Janet native libraries and applications
|
||||
easier to build without `jpm`.
|
||||
|
||||
## 1.21.2 - 2022-04-01
|
||||
- C functions `janet_dobytes` and `janet_dostring` will now enter the event loop if it is enabled.
|
||||
- Fix hashing regression - hash of negative 0 must be the same as positive 0 since they are equal.
|
||||
- The `flycheck` function no longer pollutes the module/cache
|
||||
- Fix quasiquote bug in compiler
|
||||
- Disallow use of `cancel` and `resume` on fibers scheduled or created with `ev/go`, as well as the root
|
||||
fiber.
|
||||
|
||||
## 1.20.0 - 2022-1-27
|
||||
- Add `:missing-symbol` hook to `compile` that will act as a catch-all macro for undefined symbols.
|
||||
- Add `:redef` dynamic binding that will allow users to redefine top-level bindings with late binding. This
|
||||
is intended for development use.
|
||||
- Fix a bug with reading from a stream returned by `os/open` on Windows and Linux.
|
||||
- Add `:ppc64` as a detectable OS type.
|
||||
- Add `& more` support for destructuring in the match macro.
|
||||
- Add `& more` support for destructuring in all binding forms (`def`).
|
||||
|
||||
## 1.19.2 - 2021-12-06
|
||||
- Fix bug with missing status lines in some stack traces.
|
||||
- Update hash function to have better statistical properties.
|
||||
|
||||
## 1.19.1 - 2021-12-04
|
||||
- Add an optional `prefix` parameter to `debug/stacktrace` to allow printing prettier error messages.
|
||||
- Remove appveyor for CI pipeline
|
||||
- Fixed a bug that prevented sending threaded abstracts over threaded channels.
|
||||
- Fix bug in the `map` function with arity at least 3.
|
||||
|
||||
## 1.19.0 - 2021-11-27
|
||||
- Add `math/log-gamma` to replace `math/gamma`, and change `math/gamma` to be the expected gamma function.
|
||||
- Fix leaking file-descriptors in os/spawn and os/execute.
|
||||
- Ctrl-C will now raise SIGINT.
|
||||
- Allow quoted literals in the `match` macro to behave as expected in patterns.
|
||||
- Fix windows net related bug for TCP servers.
|
||||
- Allow evaluating ev streams with dofile.
|
||||
- Fix `ev` related bug with operations on already closed file descriptors.
|
||||
- Add struct and table agnostic `getproto` function.
|
||||
- Add a number of functions related to structs.
|
||||
- Add prototypes to structs. Structs can now inherit from other structs, just like tables.
|
||||
- Create a struct with a prototype with `struct/with-proto`.
|
||||
- Deadlocked channels will no longer exit early - instead they will hang, which is more intuitive.
|
||||
|
||||
## 1.18.1 - 2021-10-16
|
||||
- Fix some documentation typos
|
||||
- Fix - Set pipes passed to subprocess to blocking mode.
|
||||
- Fix `-r` switch in repl.
|
||||
|
||||
## 1.18.0 - 2021-10-10
|
||||
- Allow `ev/cancel` to work on already scheduled fibers.
|
||||
- Fix bugs with ev/ module.
|
||||
- Add optional `base` argument to scan-number
|
||||
- Add `-i` flag to janet binary to make it easier to run image files from the command line
|
||||
- Remove `thread/` module.
|
||||
- Add `(number ...)` pattern to peg for more efficient number parsing using Janet's
|
||||
scan-number function without immediate string creation.
|
||||
|
||||
## 1.17.2 - 2021-09-18
|
||||
- Remove include of windows.h from janet.h. This caused issues on certain projects.
|
||||
- Fix formatting in doc-format to better handle special characters in signatures.
|
||||
- Fix some marshalling bugs.
|
||||
- Add optional Makefile target to install jpm as well.
|
||||
- Supervisor channels in threads will no longer include a wasteful copy of the fiber in every
|
||||
message across a thread.
|
||||
- Allow passing a closure to `ev/thread` as well as a whole fiber.
|
||||
- Allow passing a closure directly to `ev/go` to spawn fibers on the event loop.
|
||||
|
||||
## 1.17.1 - 2021-08-29
|
||||
- Fix docstring typos
|
||||
- Add `make install-jpm-git` to make jpm co-install simpler if using the Makefile.
|
||||
- Fix bugs with starting ev/threads and fiber marshaling.
|
||||
|
||||
## 1.17.0 - 2021-08-21
|
||||
- Add the `-E` flag for one-liners with the `short-fn` syntax for argument passing.
|
||||
- Add support for threaded abstract types. Threaded abstract types can easily be shared between threads.
|
||||
- Deprecate the `thread` library. Use threaded channels and ev instead.
|
||||
- Channels can now be marshalled.
|
||||
- Add the ability to close channels with `ev/chan-close` (or `:close`).
|
||||
- Add threaded channels with `ev/thread-chan`.
|
||||
- Add `JANET_FN` and `JANET_REG` macros to more easily define C functions that export their source mapping information.
|
||||
- Add `janet_interpreter_interupt` and `janet_loop1_interrupt` to interrupt the interpreter while running.
|
||||
- Add `table/clear`
|
||||
- Add build option to disable the threading library without disabling all threads.
|
||||
- Remove JPM from the main Janet distribution. Instead, JPM must be installed
|
||||
separately like any other package.
|
||||
- Fix issue with `ev/go` when called with an initial value and supervisor.
|
||||
- Add the C API functions `janet_vm_save` and `janet_vm_load` to allow
|
||||
saving and restoring the entire VM state.
|
||||
|
||||
## 1.16.1 - 2021-06-09
|
||||
- Add `maclintf` - a utility for adding linting messages when inside macros.
|
||||
- Print source code of offending line on compiler warnings and errors.
|
||||
- Fix some issues with linting and re-add missing `make docs`.
|
||||
- Allow controlling linting with dynamic bindings `:lint-warn`, `:lint-error`, and `:lint-levels`.
|
||||
- Add `-w` and `-x` command line flags to the `janet` binary to set linting thresholds.
|
||||
linting thresholds are as follows:
|
||||
- :none - will never be trigger.
|
||||
- :relaxed - will only trigger on `:relaxed` lints.
|
||||
- :normal - will trigger on `:relaxed` and `:normal` lints.
|
||||
- :strict - will trigger on `:strict`, `:normal`, and `:relaxed` lints. This will catch the most issues
|
||||
but can be distracting.
|
||||
|
||||
## 1.16.0 - 2021-05-30
|
||||
- Add color documentation to the `doc` macro - enable/disable with `(dyn :doc-color)`.
|
||||
- Remove simpler HTML docs from distribution - use website or built-in documentation instead.
|
||||
- Add compiler warnings and deprecation levels.
|
||||
- Add `as-macro` to make using macros within quasiquote easier to do hygienically.
|
||||
- Expose `JANET_OUT_OF_MEMORY` as part of the Janet API.
|
||||
- Add `native-deps` option to `declare-native` in `jpm`. This lets native libraries link to other
|
||||
native libraries when building with jpm.
|
||||
- Remove the `tarray` module. The functionality of typed arrays will be moved to an external module
|
||||
that can be installed via `jpm`.
|
||||
- Add `from-pairs` to core.
|
||||
- Add `JPM_OS_WHICH` environment variable to jpm to allow changing auto-detection behavior.
|
||||
- The flychecker will consider any top-level calls of functions that start with `define-` to
|
||||
be safe to execute and execute them. This allows certain patterns (like spork/path) to be
|
||||
better processed by the flychecker.
|
||||
|
||||
## 1.15.5 - 2021-04-25
|
||||
- Add `declare-headers` to jpm.
|
||||
- Fix error using unix pipes on BSDs.
|
||||
- Support .cc and .cxx extensions in `jpm` for C++ code.
|
||||
- Change networking code to not create as many HUP errors.
|
||||
- Add `net/shutdown` to close sockets in one direction without hang ups.
|
||||
- Update code for printing the debug repl
|
||||
|
||||
## 1.15.4 - 2021-03-16
|
||||
- Increase default nesting depth of pretty printing to `JANET_RECURSION_GUARD`
|
||||
- Update meson.build
|
||||
- Add option to automatically add shebang line in installed scripts with `jpm`.
|
||||
- Add `partition-by` and `group-by` to the core.
|
||||
- Sort keys in pretty printing output.
|
||||
|
||||
## 1.15.3 - 2021-02-28
|
||||
- Fix a fiber bug that occured in deeply nested fibers
|
||||
- Add `unref` combinator to pegs.
|
||||
- Small docstring changes.
|
||||
|
||||
## 1.15.2 - 2021-02-15
|
||||
- Fix bug in windows version of `os/spawn` and `os/execute` with setting environment variables.
|
||||
- Fix documentation typos.
|
||||
- Fix peg integer reading combinators when used with capture tags.
|
||||
|
||||
## 1.15.0 - 2021-02-08
|
||||
- Fix `gtim` and `ltim` bytecode instructions on non-integer values.
|
||||
- Clean up output of flychecking to be the same as the repl.
|
||||
- Change behavior of `debug/stacktrace` with a nil error value.
|
||||
- Add optional argument to `parser/produce`.
|
||||
- Add `no-core` option to creating standalone binaries to make execution faster.
|
||||
- Fix bug where a buffer overflow could be confused with an out of memory error.
|
||||
- Change error output to `file:line:column: message`. Column is in bytes - tabs
|
||||
are considered to have width 1 (instead of 8).
|
||||
|
||||
## 1.14.2 - 2021-01-23
|
||||
- Allow `JANET_PROFILE` env variable to load a profile before loading the repl.
|
||||
- Update `tracev` macro to allow `def` and `var` inside to work as expected.
|
||||
- Use `(dyn :peg-grammar)` for passing a default grammar to `peg/compile` instead of loading
|
||||
`default-peg-grammar` directly from the root environment.
|
||||
- Add `ev/thread` for combining threading with the event loop.
|
||||
- Add `ev/do-thread` to make `ev/thread` easier to use.
|
||||
- Automatically set supervisor channel in `net/accept-loop` and `net/server` correctly.
|
||||
|
||||
## 1.14.1 - 2021-01-18
|
||||
- Add `doc-of` for reverse documentation lookup.
|
||||
- Add `ev/give-supervsior` to send a message to the supervising channel.
|
||||
- Add `ev/gather` and `chan` argument to `ev/go`. This new argument allows "supervisor channels"
|
||||
for fibers to enable structured concurrency.
|
||||
- Make `-k` flag work on stdin if no files are given.
|
||||
- Add `flycheck` function to core.
|
||||
- Make `backmatch` and `backref` more expressive in pegs.
|
||||
- Fix buggy `string/split`.
|
||||
- Add `fiber/last-value` to get the value that was last yielded, errored, or signaled
|
||||
by a fiber.
|
||||
- Remove `:generate` verb from `loop` macros. Instead, use the `:in` verb
|
||||
which will now work on fibers as well as other data structures.
|
||||
- Define `next`, `get`, and `in` for fibers. This lets
|
||||
`each`, `map`, and similar iteration macros can now iterate over fibers.
|
||||
- Remove macro `eachy`, which can be replaced by `each`.
|
||||
- Add `dflt` argument to find-index.
|
||||
- Deprecate `file/popen` in favor of `os/spawn`.
|
||||
- Add `:all` keyword to `ev/read` and `net/read` to make them more like `file/read`. However, we
|
||||
do not provide any `:line` option as that requires buffering.
|
||||
- Change repl behavior to make Ctrl-C raise SIGINT on posix. The old behavior for Ctrl-C,
|
||||
to clear the current line buffer, has been moved to Ctrl-Q.
|
||||
- Importing modules that start with `/` is now the only way to import from project root.
|
||||
Before, this would import from / on disk. Previous imports that did not start with `.` or `/`
|
||||
are now unambiguously importing from the syspath, instead of checking both the syspath and
|
||||
the project root. This is backwards incompatible and dependencies should be updated for this.
|
||||
- Change hash function for numbers.
|
||||
- Improve error handling of `dofile`.
|
||||
- Bug fixes in networking and subprocess code.
|
||||
- Use markdown formatting in more places for docstrings.
|
||||
|
||||
## 1.13.1 - 2020-12-13
|
||||
- Pretty printing a table with a prototype will look for `:_name` instead of `:name`
|
||||
in the prototype table to tag the output.
|
||||
- `match` macro implementation changed to be tail recursive.
|
||||
- Adds a :preload loader which allows one to manually put things into `module/cache`.
|
||||
- Add `buffer/push` function.
|
||||
- Backtick delimited strings and buffers are now reindented based on the column of the
|
||||
opening delimiter. Whitespace in columns to the left of the starting column is ignored unless
|
||||
there are non-space/non-newline characters in that region, in which case the old behavior is preserved.
|
||||
- Argument to `(error)` combinator in PEGs is now optional.
|
||||
- Add `(line)` and `(column)` combinators to PEGs to capture source line and column.
|
||||
This should make error reporting a bit easier.
|
||||
- Add `merge-module` to core.
|
||||
- During installation and release, merge janetconf.h into janet.h for easier install.
|
||||
- Add `upscope` special form.
|
||||
- `os/execute` and `os/spawn` can take streams for redirecting IO.
|
||||
- Add `:parser` and `:read` parameters to `run-context`.
|
||||
- Add `os/open` if ev is enabled.
|
||||
- Add `os/pipe` if ev is enabled.
|
||||
- Add `janet_thread_current(void)` to C API
|
||||
- Add integer parsing forms to pegs. This makes parsing many binary protocols easier.
|
||||
- Lots of updates to networking code - now can use epoll (or poll) on linux and IOCP on windows.
|
||||
- Add `ev/` module. This exposes a fiber scheduler, queues, timeouts, and other functionality to users
|
||||
for single threaded cooperative scheduling and asynchronous IO.
|
||||
- Add `net/accept-loop` and `net/listen`. These functions break down `net/server` into it's essential parts
|
||||
and are more flexible. They also allow further improvements to these utility functions.
|
||||
- Various small bug fixes.
|
||||
|
||||
## 1.12.2 - 2020-09-20
|
||||
- Add janet\_try and janet\_restore to C API.
|
||||
- Fix `os/execute` regression on windows.
|
||||
- Add :pipe option to `os/spawn`.
|
||||
- Fix docstring typos.
|
||||
|
||||
## 1.12.1 - 2020-09-07
|
||||
- Make `zero?`, `one?`, `pos?`, and `neg?` polymorphic.
|
||||
- Add C++ support to jpm and improve C++ interop in janet.h.
|
||||
- Add `%t` formatter to `printf`, `string/format`, and other formatter functions.
|
||||
- Expose `janet_cfuns_prefix` in C API.
|
||||
- Add `os/proc-wait` and `os/proc-kill` for interacting with processes.
|
||||
- Add `janet_getjfile` to C API.
|
||||
- Allow redirection of stdin, stdout, and stderr by passing keywords in the env table in `os/spawn` and `os/execute`.
|
||||
- Add `os/spawn` to get a core/process back instead of an exit code as in `os/execute`.
|
||||
When called like this, `os/execute` returns immediately.
|
||||
- Add `:x` flag to os/execute to raise error when exit code is non-zero.
|
||||
- Don't run `main` when flychecking.
|
||||
- Add `:n` flag to `file/open` to raise an error if file cannot be opened.
|
||||
- Fix import macro to not try and coerce everything to a string.
|
||||
- Allow passing a second argument to `disasm`.
|
||||
- Add `cancel`. Resumes a fiber but makes it immediately error at the yield point.
|
||||
- Allow multi-line paste into built in repl.
|
||||
- Add `(curenv)`.
|
||||
- Change `net/read`, `net/chunk`, and `net/write` to raise errors in the case of failures.
|
||||
- Add `janet_continue_signal` to C API. This indirectly enables C functions that yield to the event loop
|
||||
to raise errors or other signals.
|
||||
- Update meson build script to fix bug on Debian's version of meson
|
||||
- Add `xprint`, `xprin`, `xprintf`, and `xprinf`.
|
||||
- `net/write` now raises an error message if write fails.
|
||||
- Fix issue with SIGPIPE on macOS and BSDs.
|
||||
|
||||
## 1.11.3 - 2020-08-03
|
||||
- Add `JANET_HASHSEED` environment variable when `JANET_PRF` is enabled.
|
||||
- Expose `janet_cryptorand` in C API.
|
||||
- Properly initialize PRF in default janet program
|
||||
- Add `index-of` to core library.
|
||||
- Add `-fPIC` back to core CFLAGS (non-optional when compiling default client with Makefile)
|
||||
- Fix defaults on Windows for ARM
|
||||
- Fix defaults on NetBSD.
|
||||
|
||||
## 1.11.1 - 2020-07-25
|
||||
- Fix jpm and git with multiple git installs on Windows
|
||||
- Fix importing a .so file in the current directory
|
||||
- Allow passing byte sequence types directly to typed-array constructors.
|
||||
- Fix bug sending files between threads.
|
||||
- Disable PRF by default.
|
||||
- Update the soname.
|
||||
|
||||
## 1.11.0 - 2020-07-18
|
||||
- Add `forever` macro.
|
||||
- Add `any?` predicate to core.
|
||||
- Add `jpm list-pkgs` subcommand to see which package aliases are in the listing.
|
||||
- Add `jpm list-installed` subcommand to see which packages are installed.
|
||||
- Add `math/int-min`, `math/int-max`, `math/int32-min`, and `math/int32-max` for getting integer limits.
|
||||
- The gc interval is now autotuned, to prevent very bad gc behavior.
|
||||
- Improvements to the bytecode compiler, Janet will now generate more efficient bytecode.
|
||||
- Add `peg/find`, `peg/find-all`, `peg/replace`, and `peg/replace-all`
|
||||
- Add `math/nan`
|
||||
- Add `forv` macro
|
||||
- Add `symbol/slice`
|
||||
- Add `keyword/slice`
|
||||
- Allow cross compilation with Makefile.
|
||||
- Change `compare-primitve` to `cmp` and make it more efficient.
|
||||
- Add `reverse!` for reversing an array or buffer in place.
|
||||
- `janet_dobytes` and `janet_dostring` return parse errors in \*out
|
||||
- Add `repeat` macro for iterating something n times.
|
||||
- Add `eachy` (each yield) macro for iterating a fiber.
|
||||
- Fix `:generate` verb in loop macro to accept non symbols as bindings.
|
||||
- Add `:h`, `:h+`, and `:h*` in `default-peg-grammar` for hexidecimal digits.
|
||||
- Fix `%j` formatter to print numbers precisely (using the `%.17g` format string to printf).
|
||||
|
||||
## 1.10.1 - 2020-06-18
|
||||
- Expose `janet_table_clear` in API.
|
||||
- Respect `JANET_NO_PROCESSES` define when building
|
||||
- Fix `jpm` rules having multiple copies of the same dependency.
|
||||
- Fix `jpm` install in some cases.
|
||||
- Add `array/trim` and `buffer/trim` to shrink the backing capacity of these types
|
||||
to their current length.
|
||||
|
||||
## 1.10.0 - 2020-06-14
|
||||
- Hardcode default jpm paths on install so env variables are needed in fewer cases.
|
||||
- Add `:no-compile` to `create-executable` option for jpm.
|
||||
- Fix bug with the `trace` function.
|
||||
- Add `:h`, `:a`, and `:c` flags to `thread/new` for creating new kinds of threads.
|
||||
By default, threads will now consume much less memory per thread, but sending data between
|
||||
threads may cost more.
|
||||
- Fix flychecking when using the `use` macro.
|
||||
- CTRL-C no longer exits the repl, and instead cancels the current form.
|
||||
- Various small bug fixes
|
||||
- New MSI installer instead of NSIS based installer.
|
||||
- Make `os/realpath` work on windows.
|
||||
- Add polymorphic `compare` functions for comparing numbers.
|
||||
- Add `to` and `thru` peg combinators.
|
||||
- Add `JANET_GIT` environment variable to jpm to use a specific git binary (useful mainly on windows).
|
||||
- `asm` and `disasm` functions now use keywords instead of macros for keys. Also
|
||||
some slight changes to the way constants are encoded (remove wrapping `quote` in some cases).
|
||||
- Expose current macro form inside macros as (dyn :macro-form)
|
||||
- Add `tracev` macro.
|
||||
- Fix compiler bug that emitted incorrect code in some cases for while loops that create closures.
|
||||
- Add `:fresh` option to `(import ...)` to overwrite the module cache.
|
||||
- `(range x y 0)` will return an empty array instead of hanging forever.
|
||||
- Rename `jpm repl` to `jpm debug-repl`.
|
||||
|
||||
## 1.9.1 - 2020-05-12
|
||||
- Add :prefix option to declare-source
|
||||
- Re-enable minimal builds with the debugger.
|
||||
- Add several flags for configuring Janet on different platforms.
|
||||
- Fix broken meson build from 1.9.0 and add meson to CI.
|
||||
- Fix compilation issue when nanboxing is disabled.
|
||||
|
||||
## 1.9.0 - 2020-05-10
|
||||
- Add `:ldflags` option to many jpm declare functions.
|
||||
- Add `errorf` to core.
|
||||
- Add `lenprefix` combinator to PEGs.
|
||||
- Add `%M`, `%m`, `%N`, and `%n` formatters to formatting functions. These are the
|
||||
same as `%Q`, `%q`, `%P`, and `%p`, but will not truncate long values.
|
||||
- Add `fiber/root`.
|
||||
- Add beta `net/` module to core for socket based networking.
|
||||
- Add the `parse` function to parse strings of source code more conveniently.
|
||||
- Add `jpm rule-tree` subcommand.
|
||||
- Add `--offline` flag to jpm to force use of the cache.
|
||||
- Allow sending pointers and C functions across threads via `thread/send`.
|
||||
- Fix bug in `getline`.
|
||||
- Add `sh-rule` and `sh-phony` to jpm's dialect of Janet.
|
||||
- Change C api's `janet_formatb` -> `janet_formatbv`, and add new function `janet_formatb` to C api.
|
||||
- Add `edefer` macro to core.
|
||||
- A struct/table literal/constructor with duplicate keys will use the last value given.
|
||||
Previously, this was inconsistent between tables and structs, literals and constructor functions.
|
||||
- Add debugger to core. The debugger functions are only available
|
||||
in a debug repl, and are prefixed by a `.`.
|
||||
- Add `sort-by` and `sorted-by` to core.
|
||||
- Support UTF-8 escapes in strings via `\uXXXX` or `\UXXXXXX`.
|
||||
- Add `math/erf`
|
||||
- Add `math/erfc`
|
||||
- Add `math/log1p`
|
||||
- Add `math/next`
|
||||
- Add os/umask
|
||||
- Add os/perm-int
|
||||
- Add os/perm-string
|
||||
- Add :int-permissions option for os/stat.
|
||||
- Add `jpm repl` subcommand, as well as `post-deps` macro in project.janet files.
|
||||
- Various bug fixes.
|
||||
|
||||
## 1.8.1 - 2020-03-31
|
||||
- Fix bugs for big endian systems
|
||||
- Fix 1.8.0 regression on BSDs
|
||||
|
||||
## 1.8.0 - 2020-03-29
|
||||
- Add `reduce2`, `accumulate`, and `accumulate2`.
|
||||
- Add lockfiles to `jpm` via `jpm make-lockfile` and `jpm load-lockfile`.
|
||||
- Add `os/realpath` (Not supported on windows).
|
||||
- Add `os/chmod`.
|
||||
- Add `chr` macro.
|
||||
- Allow `_` in the `match` macro to match anything without creating a binding
|
||||
or doing unification. Also change behavior of matching nil.
|
||||
- Add `:range-to` and `:down-to` verbs in the `loop` macro.
|
||||
- Fix `and` and `or` macros returning nil instead of false in some cases.
|
||||
- Allow matching successfully against nil values in the `match` macro.
|
||||
- Improve `janet_formatc` and `janet_panicf` formatters to be more like `string/format`.
|
||||
This makes it easier to make nice error messages from C.
|
||||
- Add `signal`
|
||||
- Add `fiber/can-resume?`
|
||||
- Allow fiber functions to accept arguments that are passed in via `resume`.
|
||||
- Make flychecking slightly less strict but more useful
|
||||
- Correct arity for `next`
|
||||
- Correct arity for `marshal`
|
||||
- Add `flush` and `eflush`
|
||||
- Add `prompt` and `return` on top of signal for user friendly delimited continuations.
|
||||
- Fix bug in buffer/blit when using the offset-src argument.
|
||||
- Fix segfault with malformed pegs.
|
||||
|
||||
## 1.7.0 - 2020-02-01
|
||||
- Remove `file/fileno` and `file/fdopen`.
|
||||
- Remove `==`, `not==`, `order<`, `order>`, `order<=`, and `order>=`. Instead, use the normal
|
||||
comparison and equality functions.
|
||||
- Let abstract types define a hash function and comparison/equality semantics. This lets
|
||||
abstract types much better represent value types. This adds more fields to abstract types, which
|
||||
will generate warnings when compiled against other versions.
|
||||
- Remove Emscripten build. Instead, use the amalgamated source code with a custom toolchain.
|
||||
- Update documentation.
|
||||
- Add `var-`
|
||||
- Add `module/add-paths`
|
||||
- Add `file/temp`
|
||||
- Add `mod` function to core.
|
||||
- Small bug fixes
|
||||
- Allow signaling from C functions (yielding) via janet\_signalv. This
|
||||
makes it easy to write C functions that work with event loops, such as
|
||||
in libuv or embedded in a game.
|
||||
- Add '%j' formatting option to the format family of functions.
|
||||
- Add `defer`
|
||||
- Add `assert`
|
||||
- Add `when-with`
|
||||
- Add `if-with`
|
||||
- Add completion to the default repl based on currently defined bindings. Also generally improve
|
||||
the repl keybindings.
|
||||
- Add `eachk`
|
||||
- Add `eachp`
|
||||
- Improve functionality of the `next` function. `next` now works on many different
|
||||
types, not just tables and structs. This allows for more generic data processing.
|
||||
- Fix thread module issue where sometimes decoding a message failed.
|
||||
- Fix segfault regression when macros are called with bad arity.
|
||||
|
||||
## 1.6.0 - 2019-12-22
|
||||
- Add `thread/` module to the core.
|
||||
- Allow seeding RNGs with any sequence of bytes. This provides
|
||||
a wider key space for the RNG. Exposed in C as `janet_rng_longseed`.
|
||||
- Fix issue in `resume` and similar functions that could cause breakpoints to be skipped.
|
||||
- Add a number of new math functions.
|
||||
- Improve debugger experience and capabilities. See examples/debugger.janet
|
||||
for what an interactive debugger could look like.
|
||||
- Add `debug/step` (janet\_step in the C API) for single stepping Janet bytecode.
|
||||
- The built in repl now can enter the debugger on any signal (errors, yields,
|
||||
user signals, and debug signals). To enable this, type (setdyn :debug true)
|
||||
in the repl environment.
|
||||
- When exiting the debugger, the fiber being debugged is resumed with the exit value
|
||||
of the debug session (the value returned by `(quit return-value)`, or nil if user typed Ctrl-D).
|
||||
- `(quit)` can take an optional argument that is the return value. If a module
|
||||
contains `(quit some-value)`, the value of that module returned to `(require "somemod")`
|
||||
is the return value. This lets module writers completely customize a module without writing
|
||||
a loader.
|
||||
- Add nested quasiquotation.
|
||||
- Add `os/cryptorand`
|
||||
- Add `prinf` and `eprinf` to be have like `printf` and `eprintf`. The latter two functions
|
||||
now including a trailing newline, like the other print functions.
|
||||
- Add nan?
|
||||
- Add `janet_in` to C API.
|
||||
- Add `truthy?`
|
||||
- Add `os/environ`
|
||||
- Add `buffer/fill` and `array/fill`
|
||||
- Add `array/new-filled`
|
||||
- Use `(doc)` with no arguments to see available bindings and dynamic bindings.
|
||||
- `jpm` will use `CC` and `AR` environment variables when compiling programs.
|
||||
- Add `comptime` macro for compile time evaluation.
|
||||
- Run `main` functions in scripts if they exist, just like jpm standalone binaries.
|
||||
- Add `protect` macro.
|
||||
- Add `root-env` to get the root environment table.
|
||||
- Change marshalling protocol with regard to abstract types.
|
||||
- Add `show-paths` to `jpm`.
|
||||
- Add several default patterns, like `:d` and `:s+`, to PEGs.
|
||||
- Update `jpm` path settings to make using `jpm` easier on non-global module trees.
|
||||
- Numerous small bug fixes and usability improvements.
|
||||
|
||||
### 1.5.1 - 2019-11-16
|
||||
- Fix bug when printing buffer to self in some edge cases.
|
||||
- Fix bug with `jpm` on windows.
|
||||
- Fix `update` return value.
|
||||
|
||||
## 1.5.0 - 2019-11-10
|
||||
- `os/date` now defaults to UTC.
|
||||
- Add `--test` flag to jpm to test libraries on installation.
|
||||
- Add `math/rng`, `math/rng-int`, and `math/rng-uniform`.
|
||||
- Add `in` function to index in a stricter manner. Conversely, `get` will
|
||||
now not throw errors on bad keys.
|
||||
- Indexed types and byte sequences will now error when indexed out of range or
|
||||
with bad keys.
|
||||
- Add rng functions to Janet. This also replaces the RNG behind `math/random`
|
||||
and `math/seedrandom` with a consistent, platform independent RNG.
|
||||
- Add `with-vars` macro.
|
||||
- Add the `quickbin` command to jpm.
|
||||
- Create shell.c when making the amalgamated source. This can be compiled with
|
||||
janet.c to make the janet interpreter.
|
||||
- Add `cli-main` function to the core, which invokes Janet's CLI interface.
|
||||
This basically moves what was init.janet into boot.janet.
|
||||
- Improve flychecking, and fix flychecking bugs introduced in 1.4.0.
|
||||
- Add `prin`, `eprint`, `eprintf` and `eprin` functions. The
|
||||
functions prefix with e print to `(dyn :err stderr)`
|
||||
- Print family of functions can now also print to buffers
|
||||
(before, they could only print to files.) Output can also
|
||||
be completely disabled with `(setdyn :out false)`.
|
||||
- `printf` is now a c function for optimizations in the case
|
||||
of printing to buffers.
|
||||
|
||||
## 1.4.0 - 2019-10-14
|
||||
- Add `quit` function to exit from a repl, but not always exit the entire
|
||||
application.
|
||||
- Add `update-pkgs` to jpm.
|
||||
- Integrate jpm with https://github.com/janet-lang/pkgs.git. jpm can now
|
||||
install packages based on their short names in the package listing, which
|
||||
can be customized via an env variable.
|
||||
- Add `varfn` macro
|
||||
- Add compile time arity checking when function in function call is known.
|
||||
- Added `slice` to the core library.
|
||||
- The `*/slice` family of functions now can take nil as start or end to get
|
||||
the same behavior as the defaults (0 and -1) for those parameters.
|
||||
- `string/` functions that take a pattern to search for will throw an error
|
||||
when receiving the empty string.
|
||||
- Replace (start:end) style stacktrace source position information with
|
||||
line, column. This should be more readable for humans. Also, range information
|
||||
can be recovered by re-parsing source.
|
||||
|
||||
## 1.3.1 - 2019-09-21
|
||||
- Fix some linking issues when creating executables with native dependencies.
|
||||
- jpm now runs each test script in a new interpreter.
|
||||
- Fix an issue that prevent some valid programs from compiling.
|
||||
- Add `mean` to core.
|
||||
- Abstract types that implement the `:+`, `:-`, `:*`, `:/`, `:>`, `:==`, `:<`,
|
||||
`:<=`, and `:>=` methods will work with the corresponding built-in
|
||||
arithmetic functions. This means built-in integer types can now be used as
|
||||
normal number values in many contexts.
|
||||
- Allow (length x) on typed arrays an other abstract types that implement
|
||||
the :length method.
|
||||
|
||||
## 1.3.0 - 2019-09-05
|
||||
- Add `get-in`, `put-in`, `update-in`, and `freeze` to core.
|
||||
- Add `jpm run rule` and `jpm rules` to jpm to improve utility and discoverability of jpm.
|
||||
- Remove `cook` module and move `path` module to https://github.com/janet-lang/path.git.
|
||||
The functionality in `cook` is now bundled directly in the `jpm` script.
|
||||
- Add `buffer/format` and `string/format` format flags `Q` and `q` to print colored and
|
||||
non-colored single-line values, similar to `P` and `p`.
|
||||
- Change default repl to print long sequences on one line and color stacktraces if color is enabled.
|
||||
- Add `backmatch` pattern for PEGs.
|
||||
- jpm detects if not in a Developer Command prompt on windows for a better error message.
|
||||
- jpm install git submodules in dependencies
|
||||
- Change default fiber stack limit to the maximum value of a 32 bit signed integer.
|
||||
- Some bug fixes with `jpm`
|
||||
- Fix bugs with pegs.
|
||||
- Add `os/arch` to get ISA that janet was compiled for
|
||||
- Add color to stacktraces via `(dyn :err-color)`
|
||||
|
||||
## 1.2.0 - 2019-08-08
|
||||
- Add `take` and `drop` functions that are easier to use compared to the
|
||||
existing slice functions.
|
||||
- Add optional default value to `get`.
|
||||
- Add function literal short-hand via `|` reader macro, which maps to the
|
||||
`short-fn` macro.
|
||||
- Add `int?` and `nat?` functions to the core.
|
||||
- Add `(dyn :executable)` at top level to get what used to be
|
||||
`(process/args 0)`.
|
||||
- Add `:linux` to platforms returned by `(os/which)`.
|
||||
- Update jpm to build standalone executables. Use `declare-executable` for this.
|
||||
- Add `use` macro.
|
||||
- Remove `process/args` in favor of `(dyn :args)`.
|
||||
- Fix bug with Nanbox implementation allowing users to created
|
||||
custom values of any type with typed array and marshal modules, which
|
||||
was unsafe.
|
||||
- Add `janet_wrap_number_safe` to API, for converting numbers to Janets
|
||||
where the number could be any 64 bit, user provided bit pattern. Certain
|
||||
NaN values (which a machine will never generate as a result of a floating
|
||||
point operation) are guarded against and converted to a default NaN value.
|
||||
|
||||
## 1.1.0 - 2019-07-08
|
||||
- Change semantics of `-l` flag to be import rather than dofile.
|
||||
- Fix compiler regression in top level defs with destructuring.
|
||||
- Add `table/clone`.
|
||||
- Improve `jpm` tool with git and dependency capabilities, as well as better
|
||||
module uninstalls.
|
||||
|
||||
## 1.0.0 - 2019-07-01
|
||||
- Add `with` macro for resource handling.
|
||||
- Add `propagate` function so we can "rethrow" signals after they are
|
||||
intercepted. This makes signals even more flexible.
|
||||
- Add `JANET_NO_DOCSTRINGS` and `JANET_NO_SOURCEMAPS` defines in janetconf.h
|
||||
for shrinking binary size.
|
||||
This seems to save about 50kB in most builds, so it's not usually worth it.
|
||||
- Update module system to allow relative imports. The `:cur:` pattern
|
||||
in `module/expand-path` will expand to the directory part of the current file, or
|
||||
whatever the value of `(dyn :current-file)` is. The `:dir:` pattern gets
|
||||
the directory part of the input path name.
|
||||
- Remove `:native:` pattern in `module/paths`.
|
||||
- Add `module/expand-path`
|
||||
- Remove `module/*syspath*` and `module/*headerpath*` in favor of dynamic
|
||||
bindings `:syspath` and `:headerpath`.
|
||||
- Compiled PEGs can now be marshaled and unmarshaled.
|
||||
- Change signature to `parser/state`
|
||||
- Add `:until` verb to loop.
|
||||
- Add `:p` flag to `fiber/new`.
|
||||
- Add `file/{fdopen,fileno}` functions.
|
||||
- Add `parser/clone` function.
|
||||
- Add optional argument to `parser/where` to set parser byte index.
|
||||
- Add optional `env` argument to `all-bindings` and `all-dynamics`.
|
||||
- Add scratch memory C API functions for auto-released memory on next gc.
|
||||
Scratch memory differs from normal GCed memory as it can also be freed normally
|
||||
for better performance.
|
||||
- Add API compatibility checking for modules. This will let native modules not load
|
||||
when the host program is not of a compatible version or configuration.
|
||||
- Change signature of `os/execute` to be much more flexible.
|
||||
|
||||
## 0.6.0 - 2019-05-29
|
||||
- `file/close` returns exit code when closing file opened with `file/popen`.
|
||||
- Add `os/rename`
|
||||
- Update windows installer to include tools like `jpm`.
|
||||
- Add `jpm` tool for building and managing projects.
|
||||
- Change interface to `cook` tool.
|
||||
- Add optional filters to `module/paths` to further refine import methods.
|
||||
- Add keyword arguments via `&keys` in parameter list.
|
||||
- Add `-k` flag for flychecking source.
|
||||
- Change signature to `compile` function.
|
||||
- Add `module/loaders` for custom loading functions.
|
||||
- Add external unification to `match` macro.
|
||||
- Add static library to main build.
|
||||
- Add `janet/*headerpath*` and change location of installed headers.
|
||||
- Let `partition` take strings.
|
||||
- Haiku OS support
|
||||
- Add `string/trim`, `string/trimr`, and `string/triml`.
|
||||
- Add `dofile` function.
|
||||
- Numbers require at least 1 significant digit.
|
||||
- `file/read` will return nil on end of file.
|
||||
- Fix various bugs.
|
||||
|
||||
## 0.5.0 - 2019-05-09
|
||||
- Fix some bugs with buffers.
|
||||
- Add `trace` and `untrace` to the core library.
|
||||
- Add `string/has-prefix?` and `string/has-suffix?` to string module.
|
||||
- Add simple debugger to repl that activates on errors or debug signal
|
||||
- Remove `*env*` and `*doc-width*`.
|
||||
- Add `fiber/getenv`, `fiber/setenv`, and `dyn`, and `setdyn`.
|
||||
- Add support for dynamic bindings (via the `dyn` and `setdyn` functions).
|
||||
- Change signatures of some functions like `eval` which no longer takes
|
||||
an optional environment.
|
||||
- Add printf function
|
||||
- Make `pp` configurable with dynamic binding `:pretty-format`.
|
||||
- Remove the `meta` function.
|
||||
- Add `with-dyns` for blocks with dynamic bindings assigned.
|
||||
- Allow leading and trailing newlines in backtick-delimited string (long strings).
|
||||
These newlines will not be included in the actual string value.
|
||||
|
||||
## 0.4.1 - 2019-04-14
|
||||
- Squash some bugs
|
||||
- Peg patterns can now make captures in any position in a grammar.
|
||||
- Add color to repl output
|
||||
- Add array/remove function
|
||||
- Add meson build support
|
||||
- Add int module for int types
|
||||
- Add meson build option
|
||||
- Add (break) special form and improve loop macro
|
||||
- Allow abstract types to specify custom tostring method
|
||||
- Extend C API for marshalling abstract types and other values
|
||||
- Add functions to `os` module.
|
||||
|
||||
## 0.4.0 - 2019-03-08
|
||||
- Fix a number of smaller bugs
|
||||
- Added :export option to import and require
|
||||
- Added typed arrays
|
||||
- Remove `callable?`.
|
||||
- Remove `tuple/append` and `tuple/prepend`, which may have seemed like `O(1)`
|
||||
operations. Instead, use the `splice` special to extend tuples.
|
||||
- Add `-m` flag to main client to allow specifying where to load
|
||||
system modules from.
|
||||
- Add `-c` flag to main client to allow compiling Janet modules to images.
|
||||
- Add `string/format` and `buffer/format`.
|
||||
- Remove `string/pretty` and `string/number`.
|
||||
- `make-image` function creates pre compiled images for janet. These images
|
||||
link to the core library. They can be loaded via require or manually via
|
||||
`load-image`.
|
||||
- Add bracketed tuples as tuple constructor.
|
||||
- Add partition function to core library.
|
||||
- Pre-compile core library into an image for faster startup.
|
||||
- Add methods to parser values that mirror the api.
|
||||
- Add janet\_getmethod to CAPI for easier use of method like syntax.
|
||||
- Add get/set to abstract types to allow them to behave more
|
||||
@@ -14,7 +812,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Disallow NaNs as table or struct keys
|
||||
- Update module resolution paths and format
|
||||
|
||||
## 0.3.0 - 2019-26-01
|
||||
## 0.3.0 - 2019-01-26
|
||||
- Add amalgamated build to janet for easier embedding.
|
||||
- Add os/date function
|
||||
- Add slurp and spit to core library.
|
||||
|
||||
@@ -14,7 +14,6 @@ Please read this document before making contributions.
|
||||
on how to reproduce it. If it is a compiler or language bug, please try to include a minimal
|
||||
example. This means don't post all 200 lines of code from your project, but spend some time
|
||||
distilling the problem to just the relevant code.
|
||||
* Add the `bug` tag to the issue.
|
||||
|
||||
## Contributing Changes
|
||||
|
||||
@@ -29,9 +28,14 @@ may require changes before being merged.
|
||||
run tests with `make test`. If you want to add a new test suite, simply add a file to
|
||||
the test folder and make sure it is run when`make test` is invoked.
|
||||
* Be consistent with the style. For C this means follow the indentation and style in
|
||||
other files (files have MIT license at top, 4 spaces indentation, no trailing whitespace, cuddled brackets, etc.)
|
||||
For janet code, the use lisp indentation with 2 spaces. One can use janet.vim to
|
||||
do this indentation, or approximate as close as possible.
|
||||
other files (files have MIT license at top, 4 spaces indentation, no trailing
|
||||
whitespace, cuddled brackets, etc.) Use `make format` to automatically format your C code with
|
||||
[astyle](http://astyle.sourceforge.net/astyle.html). You will probably need
|
||||
to install this, but it can be installed with most package managers.
|
||||
|
||||
For janet code, use lisp indentation with 2 spaces. One can use janet.vim to
|
||||
do this indentation, or approximate as close as possible. There is a janet formatter
|
||||
in [spork](https://github.com/janet-lang/spork.git) that can be used to format code as well.
|
||||
|
||||
## C style
|
||||
|
||||
@@ -39,8 +43,7 @@ For changes to the VM and Core code, you will probably need to know C. Janet is
|
||||
a subset of C99 that works with Microsoft Visual C++. This means most of C99 but with the following
|
||||
omissions.
|
||||
|
||||
* No Variable Length Arrays (yes these may work in newer MSVC compilers)
|
||||
* No `restrict`
|
||||
* No `restrict`
|
||||
* Certain functions in the standard library are not always available
|
||||
|
||||
In practice, this means programming for both MSVC on one hand and everything else on the other.
|
||||
@@ -51,11 +54,33 @@ Code should compile warning free and run valgrind clean. I find that these two c
|
||||
of the easiest ways to protect against a large number of bugs in an unsafe language like C. To check for
|
||||
valgrind errors, run `make valtest` and check the output for undefined or flagged behavior.
|
||||
|
||||
### Formatting
|
||||
|
||||
Use [astyle](http://astyle.sourceforge.net/astyle.html) via `make format` to
|
||||
ensure a consistent code style for C.
|
||||
|
||||
## Janet style
|
||||
|
||||
All janet code in the project should be formatted similar to the code in core.janet.
|
||||
The auto formatting from janet.vim will work well.
|
||||
|
||||
## Typo Fixing and One-Line changes
|
||||
|
||||
Typo fixes are welcome, as are simple one line fixes. Do not open many separate pull requests for each
|
||||
individual typo fix. This is incredibly annoying to deal with as someone needs to review each PR, run
|
||||
CI, and merge. Instead, accumulate batches of typo fixes into a single PR. If there are objections to
|
||||
specific changes, these can be addressed in the review process before the final merge, if the changes
|
||||
are accepted.
|
||||
|
||||
Similarly, low effort and bad faith changes are annoying to developers and such issues may be closed
|
||||
immediately without response.
|
||||
|
||||
## Contributions from Automated Tools
|
||||
|
||||
People making changes found or generated by automated tools MUST note this when opening an issue
|
||||
or creating a pull request. This can help give context to developers if the change/issue is
|
||||
confusing or nonsensical.
|
||||
|
||||
## Suggesting Changes
|
||||
|
||||
To suggest changes, open an issue on GitHub. Check GitHub for other issues
|
||||
@@ -65,4 +90,3 @@ timely manner. In short, if you want extra functionality now, then build it.
|
||||
|
||||
* Include a good description of the problem that is being solved
|
||||
* Include descriptions of potential solutions if you have some in mind.
|
||||
* Add the appropriate tags to the issue. For new features, add the `enhancement` tag.
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2019 Calvin Rose and contributors
|
||||
Copyright (c) 2023 Calvin Rose and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
446
Makefile
446
Makefile
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 Calvin Rose
|
||||
# Copyright (c) 2023 Calvin Rose
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,168 +21,238 @@
|
||||
################################
|
||||
##### Set global variables #####
|
||||
################################
|
||||
|
||||
sinclude config.mk
|
||||
PREFIX?=/usr/local
|
||||
|
||||
INCLUDEDIR=$(PREFIX)/include/janet
|
||||
LIBDIR=$(PREFIX)/lib
|
||||
BINDIR=$(PREFIX)/bin
|
||||
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1)\""
|
||||
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 -fvisibility=hidden \
|
||||
-DJANET_BUILD=$(JANET_BUILD)
|
||||
CLIBS=-lm -ldl
|
||||
JANETCONF_HEADER?=src/conf/janetconf.h
|
||||
INCLUDEDIR?=$(PREFIX)/include
|
||||
BINDIR?=$(PREFIX)/bin
|
||||
LIBDIR?=$(PREFIX)/lib
|
||||
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1 2> /dev/null || echo local)\""
|
||||
CLIBS=-lm -lpthread
|
||||
JANET_TARGET=build/janet
|
||||
JANET_BOOT=build/janet_boot
|
||||
JANET_IMPORT_LIB=build/janet.lib
|
||||
JANET_LIBRARY=build/libjanet.so
|
||||
JANET_PATH?=/usr/local/lib/janet
|
||||
JANET_STATIC_LIBRARY=build/libjanet.a
|
||||
JANET_PATH?=$(LIBDIR)/janet
|
||||
JANET_MANPATH?=$(PREFIX)/share/man/man1/
|
||||
JANET_PKG_CONFIG_PATH?=$(LIBDIR)/pkgconfig
|
||||
JANET_DIST_DIR?=janet-dist
|
||||
JANET_BOOT_FLAGS:=. JANET_PATH '$(JANET_PATH)'
|
||||
JANET_TARGET_OBJECTS=build/janet.o build/shell.o
|
||||
JPM_TAG?=master
|
||||
DEBUGGER=gdb
|
||||
SONAME_SETTER=-Wl,-soname,
|
||||
|
||||
UNAME:=$(shell uname -s)
|
||||
LDCONFIG:=ldconfig
|
||||
ifeq ($(UNAME), Darwin)
|
||||
# Add other macos/clang flags
|
||||
LDCONFIG:=
|
||||
else
|
||||
CFLAGS:=$(CFLAGS) -rdynamic
|
||||
CLIBS:=$(CLIBS) -lrt
|
||||
# For cross compilation
|
||||
HOSTCC?=$(CC)
|
||||
HOSTAR?=$(AR)
|
||||
CFLAGS?=-O2 -g
|
||||
LDFLAGS?=-rdynamic
|
||||
RUN:=$(RUN)
|
||||
|
||||
COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC
|
||||
BOOT_CFLAGS:=-DJANET_BOOTSTRAP -DJANET_BUILD=$(JANET_BUILD) -O0 $(COMMON_CFLAGS) -g
|
||||
BUILD_CFLAGS:=$(CFLAGS) $(COMMON_CFLAGS)
|
||||
|
||||
# Disable amalgamated build
|
||||
ifeq ($(JANET_NO_AMALG), 1)
|
||||
JANET_TARGET_OBJECTS+=$(patsubst src/%.c,build/%.bin.o,$(JANET_CORE_SOURCES))
|
||||
JANET_BOOT_FLAGS+=image-only
|
||||
endif
|
||||
|
||||
$(shell mkdir -p build/core build/mainclient build/webclient build/boot)
|
||||
# For installation
|
||||
LDCONFIG:=ldconfig "$(LIBDIR)"
|
||||
|
||||
# Source headers
|
||||
JANET_HEADERS=$(sort $(wildcard src/include/janet/*.h))
|
||||
JANET_LOCAL_HEADERS=$(sort $(wildcard src/*/*.h))
|
||||
# Check OS
|
||||
UNAME?=$(shell uname -s)
|
||||
ifeq ($(UNAME), Darwin)
|
||||
CLIBS:=$(CLIBS) -ldl
|
||||
SONAME_SETTER:=-Wl,-install_name,
|
||||
JANET_LIBRARY=build/libjanet.dylib
|
||||
LDCONFIG:=true
|
||||
else ifeq ($(UNAME), Linux)
|
||||
CLIBS:=$(CLIBS) -lrt -ldl
|
||||
endif
|
||||
|
||||
# Source files
|
||||
JANET_CORE_SOURCES=$(sort $(wildcard src/core/*.c))
|
||||
JANET_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c))
|
||||
JANET_WEBCLIENT_SOURCES=$(sort $(wildcard src/webclient/*.c))
|
||||
# For other unix likes, add flags here!
|
||||
ifeq ($(UNAME), Haiku)
|
||||
LDCONFIG:=true
|
||||
LDFLAGS=-Wl,--export-dynamic
|
||||
endif
|
||||
# For Android (termux)
|
||||
ifeq ($(UNAME), Linux) # uname on Darwin doesn't recognise -o
|
||||
ifeq ($(shell uname -o), Android)
|
||||
CLIBS:=$(CLIBS) -landroid-spawn
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY)
|
||||
# Mingw
|
||||
ifeq ($(findstring MINGW,$(UNAME)), MINGW)
|
||||
CLIBS:=-lws2_32 -lpsapi -lwsock32
|
||||
LDFLAGS:=-Wl,--out-implib,$(JANET_IMPORT_LIB)
|
||||
JANET_TARGET:=$(JANET_TARGET).exe
|
||||
JANET_BOOT:=$(JANET_BOOT).exe
|
||||
endif
|
||||
|
||||
##################################################################
|
||||
##### The bootstrap interpreter that compiles the core image #####
|
||||
##################################################################
|
||||
$(shell mkdir -p build/core build/c build/boot build/mainclient)
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.h
|
||||
|
||||
JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) src/boot/boot.c) \
|
||||
build/core.gen.o \
|
||||
build/boot.gen.o
|
||||
######################
|
||||
##### Name Files #####
|
||||
######################
|
||||
|
||||
build/%.boot.o: src/%.c
|
||||
$(CC) $(CFLAGS) -DJANET_BOOTSTRAP -o $@ -c $<
|
||||
JANET_HEADERS=src/include/janet.h $(JANETCONF_HEADER)
|
||||
|
||||
build/janet_boot: $(JANET_BOOT_OBJECTS)
|
||||
$(CC) $(CFLAGS) -DJANET_BOOTSTRAP -o $@ $^ $(CLIBS)
|
||||
JANET_LOCAL_HEADERS=src/core/features.h \
|
||||
src/core/util.h \
|
||||
src/core/state.h \
|
||||
src/core/gc.h \
|
||||
src/core/vector.h \
|
||||
src/core/fiber.h \
|
||||
src/core/regalloc.h \
|
||||
src/core/compile.h \
|
||||
src/core/emit.h \
|
||||
src/core/symcache.h
|
||||
|
||||
JANET_CORE_SOURCES=src/core/abstract.c \
|
||||
src/core/array.c \
|
||||
src/core/asm.c \
|
||||
src/core/buffer.c \
|
||||
src/core/bytecode.c \
|
||||
src/core/capi.c \
|
||||
src/core/cfuns.c \
|
||||
src/core/compile.c \
|
||||
src/core/corelib.c \
|
||||
src/core/debug.c \
|
||||
src/core/emit.c \
|
||||
src/core/ev.c \
|
||||
src/core/ffi.c \
|
||||
src/core/fiber.c \
|
||||
src/core/gc.c \
|
||||
src/core/inttypes.c \
|
||||
src/core/io.c \
|
||||
src/core/marsh.c \
|
||||
src/core/math.c \
|
||||
src/core/net.c \
|
||||
src/core/os.c \
|
||||
src/core/parse.c \
|
||||
src/core/peg.c \
|
||||
src/core/pp.c \
|
||||
src/core/regalloc.c \
|
||||
src/core/run.c \
|
||||
src/core/specials.c \
|
||||
src/core/state.c \
|
||||
src/core/string.c \
|
||||
src/core/strtod.c \
|
||||
src/core/struct.c \
|
||||
src/core/symcache.c \
|
||||
src/core/table.c \
|
||||
src/core/tuple.c \
|
||||
src/core/util.c \
|
||||
src/core/value.c \
|
||||
src/core/vector.c \
|
||||
src/core/vm.c \
|
||||
src/core/wrap.c
|
||||
|
||||
JANET_BOOT_SOURCES=src/boot/array_test.c \
|
||||
src/boot/boot.c \
|
||||
src/boot/buffer_test.c \
|
||||
src/boot/number_test.c \
|
||||
src/boot/system_test.c \
|
||||
src/boot/table_test.c
|
||||
JANET_BOOT_HEADERS=src/boot/tests.h
|
||||
|
||||
##########################################################
|
||||
##### The bootstrap interpreter that creates janet.c #####
|
||||
##########################################################
|
||||
|
||||
JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) $(JANET_BOOT_SOURCES))
|
||||
|
||||
$(JANET_BOOT_OBJECTS): $(JANET_BOOT_HEADERS)
|
||||
|
||||
build/%.boot.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
|
||||
$(CC) $(BOOT_CFLAGS) -o $@ -c $<
|
||||
|
||||
$(JANET_BOOT): $(JANET_BOOT_OBJECTS)
|
||||
$(CC) $(BOOT_CFLAGS) -o $@ $(JANET_BOOT_OBJECTS) $(CLIBS)
|
||||
|
||||
# Now the reason we bootstrap in the first place
|
||||
build/core_image.c: build/janet_boot
|
||||
build/janet_boot
|
||||
build/c/janet.c: $(JANET_BOOT) src/boot/boot.janet
|
||||
$(RUN) $(JANET_BOOT) $(JANET_BOOT_FLAGS) > $@
|
||||
cksum $@
|
||||
|
||||
##########################################################
|
||||
##### The main interpreter program and shared object #####
|
||||
##########################################################
|
||||
##################
|
||||
##### Quicky #####
|
||||
##################
|
||||
|
||||
JANET_CORE_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_CORE_SOURCES)) build/core_image.o
|
||||
JANET_MAINCLIENT_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_MAINCLIENT_SOURCES)) build/init.gen.o
|
||||
|
||||
# Compile the core image generated by the bootstrap build
|
||||
build/core_image.o: build/core_image.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
build/%.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
$(JANET_TARGET): $(JANET_CORE_OBJECTS) $(JANET_MAINCLIENT_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_LIBRARY): $(JANET_CORE_OBJECTS)
|
||||
$(CC) $(CFLAGS) -shared -o $@ $^ $(CLIBS)
|
||||
|
||||
######################
|
||||
##### Emscripten #####
|
||||
######################
|
||||
|
||||
EMCC=emcc
|
||||
EMCFLAGS=-std=c99 -Wall -Wextra -Isrc/include -O2 \
|
||||
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s AGGRESSIVE_VARIABLE_ELIMINATION=1 \
|
||||
-DJANET_BUILD=$(JANET_BUILD)
|
||||
JANET_EMTARGET=build/janet.js
|
||||
JANET_WEB_SOURCES=$(JANET_CORE_SOURCES) $(JANET_WEBCLIENT_SOURCES)
|
||||
JANET_EMOBJECTS=$(patsubst src/%.c,build/%.bc,$(JANET_WEB_SOURCES)) \
|
||||
build/webinit.gen.bc build/core_image.bc
|
||||
|
||||
%.gen.bc: %.gen.c
|
||||
$(EMCC) $(EMCFLAGS) -o $@ -c $<
|
||||
|
||||
build/core_image.bc: build/core_image.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(EMCC) $(EMCFLAGS) -o $@ -c $<
|
||||
|
||||
build/%.bc: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(EMCC) $(EMCFLAGS) -o $@ -c $<
|
||||
|
||||
$(JANET_EMTARGET): $(JANET_EMOBJECTS)
|
||||
$(EMCC) $(EMCFLAGS) -shared -o $@ $^
|
||||
|
||||
emscripten: $(JANET_EMTARGET)
|
||||
|
||||
#############################
|
||||
##### Generated C files #####
|
||||
#############################
|
||||
|
||||
%.gen.o: %.gen.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
build/xxd: tools/xxd.c
|
||||
$(CC) $< -o $@
|
||||
|
||||
build/core.gen.c: src/core/core.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_core
|
||||
build/init.gen.c: src/mainclient/init.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_init
|
||||
build/webinit.gen.c: src/webclient/webinit.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_webinit
|
||||
build/boot.gen.c: src/boot/boot.janet build/xxd
|
||||
build/xxd $< $@ janet_gen_boot
|
||||
build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
|
||||
$(HOSTCC) $(BUILD_CFLAGS) -o $@ -c $<
|
||||
|
||||
########################
|
||||
##### Amalgamation #####
|
||||
########################
|
||||
|
||||
amalg: build/janet.c build/janet.h build/core_image.c
|
||||
ifeq ($(UNAME), Darwin)
|
||||
SONAME=libjanet.1.29.dylib
|
||||
else
|
||||
SONAME=libjanet.so.1.29
|
||||
endif
|
||||
|
||||
build/janet.c: $(JANET_LOCAL_HEADERS) $(JANET_CORE_SOURCES) tools/amalg.janet $(JANET_TARGET)
|
||||
$(JANET_TARGET) tools/amalg.janet > $@
|
||||
|
||||
build/janet.h: src/include/janet/janet.h
|
||||
build/c/shell.c: src/mainclient/shell.c
|
||||
cp $< $@
|
||||
|
||||
build/janet.h: $(JANET_TARGET) src/include/janet.h $(JANETCONF_HEADER)
|
||||
$(RUN) ./$(JANET_TARGET) tools/patch-header.janet src/include/janet.h $(JANETCONF_HEADER) $@
|
||||
|
||||
build/janetconf.h: $(JANETCONF_HEADER)
|
||||
cp $< $@
|
||||
|
||||
build/janet.o: build/c/janet.c $(JANETCONF_HEADER) src/include/janet.h
|
||||
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@
|
||||
|
||||
build/shell.o: build/c/shell.c $(JANETCONF_HEADER) src/include/janet.h
|
||||
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@
|
||||
|
||||
$(JANET_TARGET): $(JANET_TARGET_OBJECTS)
|
||||
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_LIBRARY): $(JANET_TARGET_OBJECTS)
|
||||
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_STATIC_LIBRARY): $(JANET_TARGET_OBJECTS)
|
||||
$(HOSTAR) rcs $@ $^
|
||||
|
||||
###################
|
||||
##### Testing #####
|
||||
###################
|
||||
|
||||
# Testing assumes HOSTCC=CC
|
||||
|
||||
TEST_SCRIPTS=$(wildcard test/suite*.janet)
|
||||
|
||||
repl: $(JANET_TARGET)
|
||||
./$(JANET_TARGET)
|
||||
$(RUN) ./$(JANET_TARGET)
|
||||
|
||||
debug: $(JANET_TARGET)
|
||||
$(DEBUGGER) ./$(JANET_TARGET)
|
||||
|
||||
VALGRIND_COMMAND=valgrind --leak-check=full
|
||||
VALGRIND_COMMAND=valgrind --leak-check=full --quiet
|
||||
|
||||
valgrind: $(JANET_TARGET)
|
||||
$(VALGRIND_COMMAND) ./$(JANET_TARGET)
|
||||
|
||||
test: $(JANET_TARGET) $(TEST_PROGRAMS)
|
||||
for f in test/*.janet; do ./$(JANET_TARGET) "$$f" || exit; done
|
||||
for f in test/suite*.janet; do $(RUN) ./$(JANET_TARGET) "$$f" || exit; done
|
||||
for f in examples/*.janet; do $(RUN) ./$(JANET_TARGET) -k "$$f"; done
|
||||
|
||||
valtest: $(JANET_TARGET) $(TEST_PROGRAMS)
|
||||
for f in test/*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
|
||||
for f in test/suite*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
|
||||
for f in examples/*.janet; do ./$(JANET_TARGET) -k "$$f"; done
|
||||
|
||||
callgrind: $(JANET_TARGET)
|
||||
for f in test/*.janet; do valgrind --tool=callgrind ./$(JANET_TARGET) "$$f" || exit; done
|
||||
for f in test/suite*.janet; do valgrind --tool=callgrind ./$(JANET_TARGET) "$$f" || exit; done
|
||||
|
||||
########################
|
||||
##### Distribution #####
|
||||
@@ -190,10 +260,22 @@ callgrind: $(JANET_TARGET)
|
||||
|
||||
dist: build/janet-dist.tar.gz
|
||||
|
||||
build/janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \
|
||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) \
|
||||
build/doc.html README.md build/janet.c
|
||||
tar -czvf $@ $^
|
||||
build/janet-%.tar.gz: $(JANET_TARGET) \
|
||||
build/janet.h \
|
||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
|
||||
README.md build/c/janet.c build/c/shell.c
|
||||
mkdir -p build/$(JANET_DIST_DIR)/bin
|
||||
cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/
|
||||
mkdir -p build/$(JANET_DIST_DIR)/include
|
||||
cp build/janet.h build/$(JANET_DIST_DIR)/include/
|
||||
mkdir -p build/$(JANET_DIST_DIR)/lib/
|
||||
cp $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
|
||||
mkdir -p build/$(JANET_DIST_DIR)/man/man1/
|
||||
cp janet.1 build/$(JANET_DIST_DIR)/man/man1/janet.1
|
||||
mkdir -p build/$(JANET_DIST_DIR)/src/
|
||||
cp build/c/janet.c build/c/shell.c build/$(JANET_DIST_DIR)/src/
|
||||
cp CONTRIBUTING.md LICENSE README.md build/$(JANET_DIST_DIR)/
|
||||
cd build && tar -czvf ../$@ ./$(JANET_DIST_DIR)
|
||||
|
||||
#########################
|
||||
##### Documentation #####
|
||||
@@ -202,39 +284,117 @@ build/janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \
|
||||
docs: build/doc.html
|
||||
|
||||
build/doc.html: $(JANET_TARGET) tools/gendoc.janet
|
||||
$(JANET_TARGET) tools/gendoc.janet > build/doc.html
|
||||
$(RUN) $(JANET_TARGET) tools/gendoc.janet > build/doc.html
|
||||
|
||||
########################
|
||||
##### Installation #####
|
||||
########################
|
||||
|
||||
.INTERMEDIATE: build/janet.pc
|
||||
build/janet.pc: $(JANET_TARGET)
|
||||
echo 'prefix=$(PREFIX)' > $@
|
||||
echo 'exec_prefix=$${prefix}' >> $@
|
||||
echo 'includedir=$(INCLUDEDIR)/janet' >> $@
|
||||
echo 'libdir=$(LIBDIR)' >> $@
|
||||
echo "" >> $@
|
||||
echo "Name: janet" >> $@
|
||||
echo "Url: https://janet-lang.org" >> $@
|
||||
echo "Description: Library for the Janet programming language." >> $@
|
||||
$(RUN) $(JANET_TARGET) -e '(print "Version: " janet/version)' >> $@
|
||||
echo 'Cflags: -I$${includedir}' >> $@
|
||||
echo 'Libs: -L$${libdir} -ljanet' >> $@
|
||||
echo 'Libs.private: $(CLIBS)' >> $@
|
||||
|
||||
install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc build/janet.h
|
||||
mkdir -p '$(DESTDIR)$(BINDIR)'
|
||||
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
||||
strip -x -S '$(DESTDIR)$(BINDIR)/janet'
|
||||
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
ln -sf ./janet/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet.h'
|
||||
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
||||
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
||||
if test $(UNAME) = Darwin ; then \
|
||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib' ; \
|
||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.dylib' ; \
|
||||
ln -sf libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
||||
else \
|
||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')' ; \
|
||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so' ; \
|
||||
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
||||
fi
|
||||
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
|
||||
mkdir -p '$(DESTDIR)$(JANET_MANPATH)'
|
||||
cp janet.1 '$(DESTDIR)$(JANET_MANPATH)'
|
||||
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
||||
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||
cp '$(JANET_IMPORT_LIB)' '$(DESTDIR)$(LIBDIR)' || echo 'no import lib to install (mingw only)'
|
||||
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || echo "You can ignore this error for non-Linux systems or local installs"
|
||||
|
||||
install-jpm-git: $(JANET_TARGET)
|
||||
mkdir -p build
|
||||
rm -rf build/jpm
|
||||
git clone --depth=1 --branch='$(JPM_TAG)' https://github.com/janet-lang/jpm.git build/jpm
|
||||
cd build/jpm && PREFIX='$(PREFIX)' \
|
||||
DESTDIR=$(DESTDIR) \
|
||||
JANET_MANPATH='$(JANET_MANPATH)' \
|
||||
JANET_HEADERPATH='$(INCLUDEDIR)/janet' \
|
||||
JANET_BINPATH='$(BINDIR)' \
|
||||
JANET_LIBPATH='$(LIBDIR)' \
|
||||
$(RUN) ../../$(JANET_TARGET) ./bootstrap.janet
|
||||
|
||||
uninstall:
|
||||
-rm '$(DESTDIR)$(BINDIR)/janet'
|
||||
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet.h'
|
||||
-rm -rf '$(DESTDIR)$(LIBDIR)'/libjanet.*
|
||||
-rm '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||
-rm '$(DESTDIR)$(JANET_MANPATH)/janet.1'
|
||||
# -rm -rf '$(DESTDIR)$(JANET_PATH)'/* - err on the side of correctness here
|
||||
|
||||
#################
|
||||
##### Other #####
|
||||
#################
|
||||
|
||||
format:
|
||||
sh tools/format.sh
|
||||
|
||||
grammar: build/janet.tmLanguage
|
||||
build/janet.tmLanguage: tools/tm_lang_gen.janet $(JANET_TARGET)
|
||||
$(JANET_TARGET) $< > $@
|
||||
$(RUN) $(JANET_TARGET) $< > $@
|
||||
|
||||
compile-commands:
|
||||
# Requires pip install copmiledb
|
||||
compiledb make
|
||||
|
||||
clean:
|
||||
-rm -rf build vgcore.* callgrind.*
|
||||
-rm -rf test/install/build test/install/modpath
|
||||
|
||||
install: $(JANET_TARGET)
|
||||
mkdir -p $(BINDIR)
|
||||
cp $(JANET_TARGET) $(BINDIR)/janet
|
||||
mkdir -p $(INCLUDEDIR)
|
||||
cp $(JANET_HEADERS) $(INCLUDEDIR)
|
||||
mkdir -p $(LIBDIR)
|
||||
cp $(JANET_LIBRARY) $(LIBDIR)/libjanet.so
|
||||
mkdir -p $(JANET_PATH)
|
||||
cp tools/cook.janet $(JANET_PATH)
|
||||
cp tools/highlight.janet $(JANET_PATH)
|
||||
cp janet.1 /usr/local/share/man/man1/
|
||||
mandb
|
||||
$(LDCONFIG)
|
||||
test-install:
|
||||
echo "JPM has been removed from default install."
|
||||
|
||||
uninstall:
|
||||
-rm $(BINDIR)/../$(JANET_TARGET)
|
||||
-rm $(LIBDIR)/../$(JANET_LIBRARY)
|
||||
-rm -rf $(INCLUDEDIR)
|
||||
$(LDCONFIG)
|
||||
help:
|
||||
@echo
|
||||
@echo 'Janet: A Dynamic Language & Bytecode VM'
|
||||
@echo
|
||||
@echo Usage:
|
||||
@echo ' make Build Janet'
|
||||
@echo ' make repl Start a REPL from a built Janet'
|
||||
@echo
|
||||
@echo ' make test Test a built Janet'
|
||||
@echo ' make valgrind Assess Janet with Valgrind'
|
||||
@echo ' make callgrind Assess Janet with Valgrind, using Callgrind'
|
||||
@echo ' make valtest Run the test suite with Valgrind to check for memory leaks'
|
||||
@echo ' make dist Create a distribution tarball'
|
||||
@echo ' make docs Generate documentation'
|
||||
@echo ' make debug Run janet with GDB or LLDB'
|
||||
@echo ' make install Install into the current filesystem'
|
||||
@echo ' make uninstall Uninstall from the current filesystem'
|
||||
@echo ' make clean Clean intermediate build artifacts'
|
||||
@echo " make format Format Janet's own source files"
|
||||
@echo ' make grammar Generate a TextMate language grammar'
|
||||
@echo
|
||||
|
||||
.PHONY: clean install repl debug valgrind test amalg \
|
||||
valtest emscripten dist uninstall docs grammar \
|
||||
$(TEST_PROGRAM_PHONIES) $(TEST_PROGRAM_VALPHONIES)
|
||||
.PHONY: clean install repl debug valgrind test \
|
||||
valtest dist uninstall docs grammar format help compile-commands
|
||||
|
||||
473
README.md
473
README.md
@@ -1,190 +1,401 @@
|
||||
[](https://gitter.im/janet-language/community)
|
||||
|
||||
[](https://travis-ci.org/janet-lang/janet)
|
||||
[](https://ci.appveyor.com/project/janet-lang/janet)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/master/freebsd.yml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/master/openbsd.yml?)
|
||||
[](https://github.com/janet-lang/janet/actions/workflows/test.yml)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
|
||||
|
||||
**Janet** is a functional and imperative programming language and bytecode interpreter. It is a
|
||||
modern lisp, but lists are replaced
|
||||
by other data structures with better utility and performance (arrays, tables, structs, tuples).
|
||||
The language also bridging bridging to native code written in C, meta-programming with macros, and bytecode assembly.
|
||||
**Janet** is a programming language for system scripting, expressive automation, and
|
||||
extending programs written in C or C++ with user scripting capabilities.
|
||||
|
||||
There is a repl for trying out the language, as well as the ability
|
||||
Janet makes a good system scripting language, or a language to embed in other programs.
|
||||
It's like Lua and GNU Guile in that regard. It has more built-in functionality and a richer core language than
|
||||
Lua, but smaller than GNU Guile or Python. However, it is much easier to embed and port than Python or Guile.
|
||||
|
||||
There is a REPL for trying out the language, as well as the ability
|
||||
to run script files. This client program is separate from the core runtime, so
|
||||
janet could be embedded into other programs. Try janet in your browser at
|
||||
[https://janet-lang.org](https://janet-lang.org).
|
||||
Janet can be embedded in other programs. Try Janet in your browser at
|
||||
<https://janet-lang.org>.
|
||||
|
||||
#
|
||||
If you'd like to financially support the ongoing development of Janet, consider
|
||||
[sponsoring its primary author](https://github.com/sponsors/bakpakin) through GitHub.
|
||||
|
||||
Implemented in mostly standard C99, janet runs on Windows, Linux and macOS.
|
||||
The few features that are not standard C (dynamic library loading, compiler specific optimizations),
|
||||
are fairly straight forward. Janet can be easily ported to new platforms.
|
||||
<br>
|
||||
|
||||
For syntax highlighting, there is some preliminary vim syntax highlighting in [janet.vim](https://github.com/janet-lang/janet.vim).
|
||||
Generic lisp syntax highlighting should, however, provide good results. One can also generate a janet.tmLanguage
|
||||
file for other programs with `make grammar`.
|
||||
## Examples
|
||||
|
||||
## Use Cases
|
||||
See the examples directory for all provided example programs.
|
||||
|
||||
Janet makes a good system scripting language, or a language to embed in other programs. Think Lua or Guile.
|
||||
### Game of Life
|
||||
|
||||
## Features
|
||||
```janet
|
||||
# John Conway's Game of Life
|
||||
|
||||
* Minimal setup - one binary and you are good to go!
|
||||
* First class closures
|
||||
(def- window
|
||||
(seq [x :range [-1 2]
|
||||
y :range [-1 2]
|
||||
:when (not (and (zero? x) (zero? y)))]
|
||||
[x y]))
|
||||
|
||||
(defn- neighbors
|
||||
[[x y]]
|
||||
(map (fn [[x1 y1]] [(+ x x1) (+ y y1)]) window))
|
||||
|
||||
(defn tick
|
||||
"Get the next state in the Game Of Life."
|
||||
[state]
|
||||
(def cell-set (frequencies state))
|
||||
(def neighbor-set (frequencies (mapcat neighbors state)))
|
||||
(seq [coord :keys neighbor-set
|
||||
:let [count (get neighbor-set coord)]
|
||||
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
|
||||
coord))
|
||||
|
||||
(defn draw
|
||||
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
|
||||
[state x1 y1 x2 y2]
|
||||
(def cellset @{})
|
||||
(each cell state (put cellset cell true))
|
||||
(loop [x :range [x1 (+ 1 x2)]
|
||||
:after (print)
|
||||
y :range [y1 (+ 1 y2)]]
|
||||
(file/write stdout (if (get cellset [x y]) "X " ". ")))
|
||||
(print))
|
||||
|
||||
# Print the first 20 generations of a glider
|
||||
(var *state* '[(0 0) (-1 0) (1 0) (1 1) (0 2)])
|
||||
(for i 0 20
|
||||
(print "generation " i)
|
||||
(draw *state* -7 -7 7 7)
|
||||
(set *state* (tick *state*)))
|
||||
```
|
||||
|
||||
### TCP Echo Server
|
||||
|
||||
```janet
|
||||
# A simple TCP echo server using the built-in socket networking and event loop.
|
||||
|
||||
(defn handler
|
||||
"Simple handler for connections."
|
||||
[stream]
|
||||
(defer (:close stream)
|
||||
(def id (gensym))
|
||||
(def b @"")
|
||||
(print "Connection " id "!")
|
||||
(while (:read stream 1024 b)
|
||||
(printf " %v -> %v" id b)
|
||||
(:write stream b)
|
||||
(buffer/clear b))
|
||||
(printf "Done %v!" id)
|
||||
(ev/sleep 0.5)))
|
||||
|
||||
(net/server "127.0.0.1" "8000" handler)
|
||||
```
|
||||
|
||||
### Windows FFI Hello, World!
|
||||
|
||||
```janet
|
||||
# Use the FFI to popup a Windows message box - no C required
|
||||
|
||||
(ffi/context "user32.dll")
|
||||
|
||||
(ffi/defbind MessageBoxA :int
|
||||
[w :ptr text :string cap :string typ :int])
|
||||
|
||||
(MessageBoxA nil "Hello, World!" "Test" 0)
|
||||
```
|
||||
|
||||
## Language Features
|
||||
|
||||
* 600+ functions and macros in the core library
|
||||
* Built-in socket networking, threading, subprocesses, and file system functions.
|
||||
* Parsing Expression Grammars (PEG) engine as a more robust Regex alternative
|
||||
* Macros and compile-time computation
|
||||
* Per-thread event loop for efficient IO (epoll/IOCP/kqueue)
|
||||
* First-class green threads (continuations) as well as OS threads
|
||||
* Erlang-style supervision trees that integrate with the event loop
|
||||
* First-class closures
|
||||
* Garbage collection
|
||||
* First class green threads (continuations)
|
||||
* Python style generators (implemented as a plain macro)
|
||||
* Distributed as janet.c and janet.h for embedding into a larger program.
|
||||
* Python-style generators (implemented as a plain macro)
|
||||
* Mutable and immutable arrays (array/tuple)
|
||||
* Mutable and immutable hashtables (table/struct)
|
||||
* Mutable and immutable strings (buffer/string)
|
||||
* Lisp Macros
|
||||
* Byte code interpreter with an assembly interface, as well as bytecode verification
|
||||
* Tailcall Optimization
|
||||
* Direct interop with C via abstract types and C functions
|
||||
* Dynamically load C libraries
|
||||
* Functional and imperative standard library
|
||||
* Lexical scoping
|
||||
* Imperative programming as well as functional
|
||||
* REPL
|
||||
* Parsing Expression Grammars built in to the core library
|
||||
* 300+ functions and macros in the core library
|
||||
* Embedding Janet in other programs
|
||||
* Interactive environment with detailed stack traces
|
||||
* Tail recursion
|
||||
* Interface with C functions and dynamically load plugins ("natives").
|
||||
* Built-in C FFI for when the native bindings are too much work
|
||||
* REPL development with debugger and inspectable runtime
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation can be found in the doc directory of
|
||||
the repository. There is an introduction
|
||||
section contains a good overview of the language.
|
||||
* For a quick tutorial, see [the introduction](https://janet-lang.org/docs/index.html) for more details.
|
||||
* For the full API for all functions in the core library, see [the core API doc](https://janet-lang.org/api/index.html).
|
||||
|
||||
API documentation for all bindings can also be generated
|
||||
with `make docs`, which will create `build/doc.html`, which
|
||||
can be viewed with any web browser. This
|
||||
includes all forms in the core library except special forms.
|
||||
|
||||
For individual bindings from within the REPL, use the `(doc symbol-name)` macro to get API
|
||||
documentation for the core library. For example,
|
||||
Documentation is also available locally in the REPL.
|
||||
Use the `(doc symbol-name)` macro to get API
|
||||
documentation for symbols in the core library. For example,
|
||||
```
|
||||
(doc doc)
|
||||
(doc apply)
|
||||
```
|
||||
Shows documentation for the doc macro.
|
||||
shows documentation for the `apply` function.
|
||||
|
||||
To get a list of all bindings in the default
|
||||
environment, use the `(all-symbols)` function.
|
||||
environment, use the `(all-bindings)` function. You
|
||||
can also use the `(doc)` macro with no arguments if you are in the REPL
|
||||
to show bound symbols.
|
||||
|
||||
## Installation
|
||||
## Source
|
||||
|
||||
Install a stable version of janet from the [releases page](https://github.com/janet-lang/janet/releases).
|
||||
Janet is prebuilt for a few systems, but if you want to develop janet, run janet on a non-x86 system, or
|
||||
get the latest, you must build janet from source. Janet is in alpha and may change
|
||||
in backwards incompatible ways.
|
||||
You can get the source on [GitHub](https://github.com/janet-lang/janet) or
|
||||
[SourceHut](https://git.sr.ht/~bakpakin/janet). While the GitHub repo is the official repo,
|
||||
the SourceHut mirror is actively maintained.
|
||||
|
||||
## Usage
|
||||
## Building
|
||||
|
||||
A repl is launched when the binary is invoked with no arguments. Pass the -h flag
|
||||
to display the usage information. Individual scripts can be run with `./janet myscript.janet`
|
||||
### macOS and Unix-like
|
||||
|
||||
If you are looking to explore, you can print a list of all available macros, functions, and constants
|
||||
by entering the command `(all-bindings)` into the repl.
|
||||
|
||||
```
|
||||
$ ./janet
|
||||
Janet 0.0.0 alpha Copyright (C) 2017-2018 Calvin Rose
|
||||
janet:1:> (+ 1 2 3)
|
||||
6
|
||||
janet:2:> (print "Hello, World!")
|
||||
Hello, World!
|
||||
nil
|
||||
janet:3:> (os.exit)
|
||||
$ ./janet -h
|
||||
usage: ./janet [options] scripts...
|
||||
Options are:
|
||||
-h Show this help
|
||||
-v Print the version string
|
||||
-s Use raw stdin instead of getline like functionality
|
||||
-e Execute a string of janet
|
||||
-r Enter the repl after running all scripts
|
||||
-p Keep on executing if there is a top level error (persistent)
|
||||
-- Stop handling option
|
||||
$
|
||||
```
|
||||
|
||||
## Embedding
|
||||
|
||||
The C API for Janet is not yet documented but coming soon.
|
||||
|
||||
Janet can be embedded in a host program very easily. There is a make target `make amalg`
|
||||
which creates the file `build/janet.c`, which is a single C file that contains all the source
|
||||
to Janet. This file, along with `src/include/janet/janet.h` can dragged into any C project
|
||||
and compiled into the project. Janet should be compiled with `-std=c99` on most compilers, and
|
||||
will need to be linked to the math library, `-lm`, and the dynamic linker, `-ldl`, if one wants
|
||||
to be able to load dynamic modules. If there is no need for dynamic modules, add the define
|
||||
`-DJANET_NO_DYNAMIC_MODULES` to the compiler options.
|
||||
|
||||
## Compiling and Running
|
||||
|
||||
Janet only uses Make and batch files to compile on Posix and windows
|
||||
respectively. To configure janet, edit the header file src/include/janet/janet.h
|
||||
before compilation.
|
||||
|
||||
### macos and Unix-like
|
||||
|
||||
On most platforms, use Make to build janet. The resulting binary will be in `build/janet`.
|
||||
The Makefile is non-portable and requires GNU-flavored make.
|
||||
|
||||
```sh
|
||||
cd somewhere/my/projects/janet
|
||||
make
|
||||
make test
|
||||
make repl
|
||||
make install
|
||||
make install-jpm-git
|
||||
```
|
||||
|
||||
After building, run `make install` to install the janet binary and libs.
|
||||
Will install in `/usr/local` by default, see the Makefile to customize.
|
||||
Find out more about the available make targets by running `make help`.
|
||||
|
||||
It's also recommended to set the `JANET_PATH` variable in your profile.
|
||||
This is where janet will look for imported libraries after the current directory.
|
||||
### 32-bit Haiku
|
||||
|
||||
32-bit Haiku build instructions are the same as the UNIX-like build instructions,
|
||||
but you need to specify an alternative compiler, such as `gcc-x86`.
|
||||
|
||||
```sh
|
||||
cd somewhere/my/projects/janet
|
||||
make CC=gcc-x86
|
||||
make test
|
||||
make repl
|
||||
make install
|
||||
make install-jpm-git
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
|
||||
FreeBSD build instructions are the same as the unix-like build instuctions,
|
||||
but you need `gmake` and `gcc` to compile.
|
||||
FreeBSD build instructions are the same as the UNIX-like build instructions,
|
||||
but you need `gmake` to compile. Alternatively, install the package directly with `pkg install lang/janet`.
|
||||
|
||||
```
|
||||
```sh
|
||||
cd somewhere/my/projects/janet
|
||||
gmake CC=gcc
|
||||
gmake test CC=gcc
|
||||
gmake
|
||||
gmake test
|
||||
gmake repl
|
||||
gmake install
|
||||
gmake install-jpm-git
|
||||
```
|
||||
|
||||
### NetBSD
|
||||
|
||||
NetBSD build instructions are the same as the FreeBSD build instructions.
|
||||
Alternatively, install the package directly with `pkgin install janet`.
|
||||
|
||||
### Windows
|
||||
|
||||
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15#)
|
||||
or [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15#)
|
||||
2. Run a Visual Studio Command Prompt (cl.exe and link.exe need to be on the PATH) and cd to the directory with janet.
|
||||
3. Run `build_win` to compile janet.
|
||||
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15#) or [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15#).
|
||||
2. Run a Visual Studio Command Prompt (`cl.exe` and `link.exe` need to be on your PATH) and `cd` to the directory with Janet.
|
||||
3. Run `build_win` to compile Janet.
|
||||
4. Run `build_win test` to make sure everything is working.
|
||||
|
||||
### Emscripten
|
||||
To build an `.msi` installer executable, in addition to the above steps, you will have to:
|
||||
|
||||
To build janet for the web via [Emscripten](https://kripken.github.io/emscripten-site/), make sure you
|
||||
have `emcc` installed and on your path. On a linux or macOS system, use `make emscripten` to build
|
||||
`janet.js` and `janet.wasm` - both are needed to run janet in a browser or in node.
|
||||
The JavaScript build is what runs the repl on the main website,
|
||||
but really serves mainly as a proof of concept. Janet will run slower in a browser.
|
||||
Building with emscripten on windows is currently unsupported.
|
||||
5. Install, or otherwise add to your PATH the [WiX 3.11 Toolset](https://github.com/wixtoolset/wix3/releases).
|
||||
6. Run `build_win dist`.
|
||||
|
||||
## Examples
|
||||
Now you should have an `.msi`. You can run `build_win install` to install the `.msi`, or execute the file itself.
|
||||
|
||||
See the examples directory for some example janet code.
|
||||
### Meson
|
||||
|
||||
Janet also has a build file for [Meson](https://mesonbuild.com/), a cross-platform build
|
||||
system. Although Meson has a Python dependency, Meson is a very complete build system that
|
||||
is maybe more convenient and flexible for integrating into existing pipelines.
|
||||
Meson also provides much better IDE integration than Make or batch files, as well as support
|
||||
for cross-compilation.
|
||||
|
||||
For the impatient, building with Meson is as follows. The options provided to
|
||||
`meson setup` below emulate Janet's Makefile.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/janet-lang/janet.git
|
||||
cd janet
|
||||
meson setup build \
|
||||
--buildtype release \
|
||||
--optimization 2 \
|
||||
--libdir /usr/local/lib \
|
||||
-Dgit_hash=$(git log --pretty=format:'%h' -n 1)
|
||||
ninja -C build
|
||||
|
||||
# Run the binary
|
||||
build/janet
|
||||
|
||||
# Installation
|
||||
ninja -C build install
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Janet can be hacked on with pretty much any environment you like, but for IDE
|
||||
lovers, [Gnome Builder](https://wiki.gnome.org/Apps/Builder) is probably the
|
||||
best option, as it has excellent Meson integration. It also offers code completion
|
||||
for Janet's C API right out of the box, which is very useful for exploring. VSCode, Vim,
|
||||
Emacs, and Atom each have syntax packages for the Janet language, though.
|
||||
|
||||
## Installation
|
||||
|
||||
See the [Introduction](https://janet-lang.org/docs/index.html) for more details. If you just want
|
||||
to try out the language, you don't need to install anything. You can also move the `janet` executable wherever you want on your system and run it.
|
||||
|
||||
## Usage
|
||||
|
||||
A REPL is launched when the binary is invoked with no arguments. Pass the `-h` flag
|
||||
to display the usage information. Individual scripts can be run with `./janet myscript.janet`.
|
||||
|
||||
If you are looking to explore, you can print a list of all available macros, functions, and constants
|
||||
by entering the command `(all-bindings)` into the REPL.
|
||||
|
||||
```
|
||||
$ janet
|
||||
Janet 1.7.1-dev-951e10f Copyright (C) 2017-2020 Calvin Rose
|
||||
janet:1:> (+ 1 2 3)
|
||||
6
|
||||
janet:2:> (print "Hello, World!")
|
||||
Hello, World!
|
||||
nil
|
||||
janet:3:> (os/exit)
|
||||
$ janet -h
|
||||
usage: janet [options] script args...
|
||||
Options are:
|
||||
-h : Show this help
|
||||
-v : Print the version string
|
||||
-s : Use raw stdin instead of getline like functionality
|
||||
-e code : Execute a string of janet
|
||||
-E code arguments... : Evaluate an expression as a short-fn with arguments
|
||||
-d : Set the debug flag in the REPL
|
||||
-r : Enter the REPL after running all scripts
|
||||
-R : Disables loading profile.janet when JANET_PROFILE is present
|
||||
-p : Keep on executing if there is a top-level error (persistent)
|
||||
-q : Hide logo (quiet)
|
||||
-k : Compile scripts but do not execute (flycheck)
|
||||
-m syspath : Set system path for loading global modules
|
||||
-c source output : Compile janet source code into an image
|
||||
-i : Load the script argument as an image file instead of source code
|
||||
-n : Disable ANSI color output in the REPL
|
||||
-l lib : Use a module before processing more arguments
|
||||
-w level : Set the lint warning level - default is "normal"
|
||||
-x level : Set the lint error level - default is "none"
|
||||
-- : Stop handling options
|
||||
```
|
||||
|
||||
If installed, you can also run `man janet` to get usage information.
|
||||
|
||||
## Embedding
|
||||
|
||||
Janet can be embedded in a host program very easily. The normal build
|
||||
will create a file `build/janet.c`, which is a single C file
|
||||
that contains all the source to Janet. This file, along with
|
||||
`src/include/janet.h` and `src/conf/janetconf.h`, can be dragged into any C
|
||||
project and compiled into it. Janet should be compiled with `-std=c99`
|
||||
on most compilers, and will need to be linked to the math library, `-lm`, and
|
||||
the dynamic linker, `-ldl`, if one wants to be able to load dynamic modules. If
|
||||
there is no need for dynamic modules, add the define
|
||||
`-DJANET_NO_DYNAMIC_MODULES` to the compiler options.
|
||||
|
||||
See the [Embedding Section](https://janet-lang.org/capi/embedding.html) on the website for more information.
|
||||
|
||||
## Discussion
|
||||
|
||||
Feel free to ask questions and join discussion on the [Janet Gitter Channel](https://gitter.im/janet-language/community).
|
||||
Alternatively, check out [the #janet channel on Freenode](https://webchat.freenode.net/)
|
||||
Feel free to ask questions and join the discussion on the [Janet Gitter channel](https://gitter.im/janet-language/community).
|
||||
Gitter provides Matrix and IRC bridges as well.
|
||||
|
||||
## Why Janet
|
||||
## FAQ
|
||||
|
||||
### How fast is it?
|
||||
|
||||
It is about the same speed as most interpreted languages without a JIT compiler. Tight, critical
|
||||
loops should probably be written in C or C++ . Programs tend to be a bit faster than
|
||||
they would be in a language like Python due to the discouragement of slow Object-Oriented abstraction
|
||||
with lots of hash-table lookups, and making late-binding explicit. All values are boxed in an 8-byte
|
||||
representation by default and allocated on the heap, with the exception of numbers, nils and booleans. The
|
||||
PEG engine is a specialized interpreter that can efficiently process string and buffer data.
|
||||
|
||||
The GC is simple and stop-the-world, but GC knobs are exposed in the core library and separate threads
|
||||
have isolated heaps and garbage collectors. Data that is shared between threads is reference counted.
|
||||
|
||||
YMMV.
|
||||
|
||||
### Where is (favorite feature from other language)?
|
||||
|
||||
It may exist, it may not. If you want to propose a major language feature, go ahead and open an issue, but
|
||||
it will likely be closed as "will not implement". Often, such features make one usecase simpler at the expense
|
||||
of 5 others by making the language more complicated.
|
||||
|
||||
### Is there a language spec?
|
||||
|
||||
There is not currently a spec besides the documentation at <https://janet-lang.org>.
|
||||
|
||||
### Is this Scheme/Common Lisp? Where are the cons cells?
|
||||
|
||||
Nope. There are no cons cells here.
|
||||
|
||||
### Is this a Clojure port?
|
||||
|
||||
No. It's similar to Clojure superficially because I like Lisps and I like the aesthetics.
|
||||
Internally, Janet is not at all like Clojure, Scheme, or Common Lisp.
|
||||
|
||||
### Are the immutable data structures (tuples and structs) implemented as hash tries?
|
||||
|
||||
No. They are immutable arrays and hash tables. Don't try and use them like Clojure's vectors
|
||||
and maps, instead they work well as table keys or other identifiers.
|
||||
|
||||
### Can I do object-oriented programming with Janet?
|
||||
|
||||
To some extent, yes. However, it is not the recommended method of abstraction, and performance may suffer.
|
||||
That said, tables can be used to make mutable objects with inheritance and polymorphism, where object
|
||||
methods are implemented with keywords.
|
||||
|
||||
```clj
|
||||
(def Car @{:honk (fn [self msg] (print "car " self " goes " msg)) })
|
||||
(def my-car (table/setproto @{} Car))
|
||||
(:honk my-car "Beep!")
|
||||
```
|
||||
|
||||
### Why can't we add (feature from Clojure) into the core?
|
||||
|
||||
Usually, one of a few reasons:
|
||||
- Often, it already exists in a different form and the Clojure port would be redundant.
|
||||
- Clojure programs often generate a lot of garbage and rely on the JVM to clean it up.
|
||||
Janet does not run on the JVM and has a more primitive garbage collector.
|
||||
- We want to keep the Janet core small. With Lisps, a feature can usually be added as a library
|
||||
without feeling "bolted on", especially when compared to ALGOL-like languages. Adding features
|
||||
to the core also makes it a bit more difficult to keep Janet maximally portable.
|
||||
|
||||
### Can I bind to Rust/Zig/Go/Java/Nim/C++/D/Pascal/Fortran/Odin/Jai/(Some new "Systems" Programming Language)?
|
||||
|
||||
Probably, if that language has a good interface with C. But the programmer may need to do
|
||||
some extra work to map Janet's internal memory model may need some to that of the bound language. Janet
|
||||
also uses `setjmp`/`longjmp` for non-local returns internally. This
|
||||
approach is out of favor with many programmers now and doesn't always play well with other languages
|
||||
that have exceptions or stack-unwinding.
|
||||
|
||||
### Why is my terminal spitting out junk when I run the REPL?
|
||||
|
||||
Make sure your terminal supports ANSI escape codes. Most modern terminals will
|
||||
support these, but some older terminals, Windows consoles, or embedded terminals
|
||||
will not. If your terminal does not support ANSI escape codes, run the REPL with
|
||||
the `-n` flag, which disables color output. You can also try the `-s` flag if further issues
|
||||
ensue.
|
||||
|
||||
## Why is it called "Janet"?
|
||||
|
||||
Janet is named after the almost omniscient and friendly artificial being in [The Good Place](https://en.wikipedia.org/wiki/The_Good_Place).
|
||||
|
||||
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-the-good-place.gif" alt="Janet logo" width="115px" align="left">
|
||||
|
||||
|
||||
48
appveyor.yml
48
appveyor.yml
@@ -1,48 +0,0 @@
|
||||
version: build-{build}
|
||||
clone_folder: c:\projects\janet
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
configuration:
|
||||
- Release
|
||||
- Debug
|
||||
platform:
|
||||
- x64
|
||||
environment:
|
||||
matrix:
|
||||
- arch: Win64
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
# skip unsupported combinations
|
||||
init:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
|
||||
install:
|
||||
- build_win
|
||||
- build_win test
|
||||
- choco install nsis -y -pre
|
||||
- call "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi
|
||||
- build_win dist
|
||||
- copy janet-install.exe dist\install.exe
|
||||
|
||||
build: off
|
||||
|
||||
only_commits:
|
||||
files:
|
||||
- appveyor.yml
|
||||
- src/
|
||||
|
||||
artifacts:
|
||||
- path: dist
|
||||
name: janet-windows
|
||||
type: Zip
|
||||
|
||||
deploy:
|
||||
description: 'The Janet Programming Language.'
|
||||
provider: GitHub
|
||||
auth_token:
|
||||
secure: lwEXy09qhj2jSH9s1C/KvCkAUqJSma8phFR+0kbsfUc3rVxpNK5uD3z9Md0SjYRx
|
||||
artifact: janet-windows
|
||||
draft: true
|
||||
on:
|
||||
APPVEYOR_REPO_TAG: true
|
||||
BIN
assets/icon.ico
Normal file
BIN
assets/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
11
assets/icon_svg.svg
Normal file
11
assets/icon_svg.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 640 640" preserveAspectRatio="xMidYMid meet">
|
||||
<g id="layer101" fill="#d45500" stroke="none">
|
||||
<path d="M145 531 c-46 -31 -58 -75 -30 -118 21 -32 30 -22 44 47 7 30 19 62 27 71 26 29 1 29 -41 0z"/>
|
||||
<path d="M341 534 c-23 -29 -26 -50 -11 -88 10 -28 64 -60 86 -52 12 5 12 2 0 -22 -24 -47 -51 -64 -116 -71 -51 -6 -65 -12 -85 -37 -14 -16 -24 -32 -25 -36 0 -12 -35 -9 -48 4 -7 7 -12 24 -12 38 0 41 -11 43 -47 8 -47 -46 -46 -90 5 -138 20 -19 49 -51 63 -70 l27 -35 88 0 c49 0 106 4 127 8 46 10 106 62 143 125 25 42 28 58 30 142 0 52 4 103 9 113 11 27 -14 75 -49 93 -41 21 -115 44 -143 44 -12 0 -31 -12 -42 -26z m89 -119 c0 -3 -2 -5 -5 -5 -3 0 -5 2 -5 5 0 3 2 5 5 5 3 0 5 -2 5 -5z"/>
|
||||
</g>
|
||||
<g id="layer102" fill="#deaa87" stroke="none">
|
||||
<path d="M186 549 c-33 -31 -38 -43 -56 -137 -26 -135 -26 -163 3 -190 33 -31 49 -28 85 17 28 35 36 39 87 43 46 4 61 10 90 38 18 18 39 46 46 62 10 25 9 32 -5 46 -17 16 -19 16 -29 1 -8 -14 -15 -15 -34 -6 -27 12 -40 65 -24 96 10 17 8 23 -12 36 -13 8 -44 18 -69 21 -42 6 -49 4 -82 -27z"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 109 KiB |
136
build_win.bat
136
build_win.bat
@@ -13,70 +13,59 @@
|
||||
@if "%1"=="clean" goto CLEAN
|
||||
@if "%1"=="test" goto TEST
|
||||
@if "%1"=="dist" goto DIST
|
||||
@if "%1"=="install" goto INSTALL
|
||||
@if "%1"=="all" goto ALL
|
||||
|
||||
@rem Set compile and link options here
|
||||
@setlocal
|
||||
@set JANET_COMPILE=cl /nologo /Isrc\include /c /O2 /W3 /LD /D_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
@rem Example use asan
|
||||
@rem set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD /fsanitize=address /Zi
|
||||
@rem set JANET_LINK=link /nologo clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib
|
||||
|
||||
@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD
|
||||
@set JANET_LINK=link /nologo
|
||||
|
||||
mkdir build
|
||||
mkdir build\core
|
||||
mkdir build\mainclient
|
||||
mkdir build\boot
|
||||
@set JANET_LINK_STATIC=lib /nologo
|
||||
|
||||
@rem Build the xxd tool for generating sources
|
||||
@cl /nologo /c tools/xxd.c /Fobuild\xxd.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@link /nologo /out:build\xxd.exe build\xxd.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@rem Add janet build tag
|
||||
if not "%JANET_BUILD%" == "" (
|
||||
@set JANET_COMPILE=%JANET_COMPILE% /DJANET_BUILD="\"%JANET_BUILD%\""
|
||||
)
|
||||
|
||||
@rem Generate the embedded sources
|
||||
@build\xxd.exe src\core\core.janet build\core.gen.c janet_gen_core
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@build\xxd.exe src\mainclient\init.janet build\init.gen.c janet_gen_init
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@build\xxd.exe src\boot\boot.janet build\boot.gen.c janet_gen_boot
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
if not exist build mkdir build
|
||||
if not exist build\core mkdir build\core
|
||||
if not exist build\c mkdir build\c
|
||||
if not exist build\boot mkdir build\boot
|
||||
|
||||
@rem Build the generated sources
|
||||
@%JANET_COMPILE% /Fobuild\core\core.gen.obj build\core.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@%JANET_COMPILE% /Fobuild\mainclient\init.gen.obj build\init.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@%JANET_COMPILE% /Fobuild\boot\boot.gen.obj build\boot.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build the bootstrap interpretter
|
||||
@rem Build the bootstrap interpreter
|
||||
for %%f in (src\core\*.c) do (
|
||||
@%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
|
||||
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
for %%f in (src\boot\*.c) do (
|
||||
@%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
|
||||
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
build\janet_boot
|
||||
|
||||
@rem Build the core image
|
||||
@%JANET_COMPILE% /Fobuild\core_image.obj build\core_image.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
build\janet_boot . > build\c\janet.c
|
||||
|
||||
@rem Build the sources
|
||||
for %%f in (src\core\*.c) do (
|
||||
@%JANET_COMPILE% /Fobuild\core\%%~nf.obj %%f
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
%JANET_COMPILE% /Fobuild\janet.obj build\c\janet.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
%JANET_COMPILE% /Fobuild\shell.obj src\mainclient\shell.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build the main client
|
||||
for %%f in (src\mainclient\*.c) do (
|
||||
@%JANET_COMPILE% /Fobuild\mainclient\%%~nf.obj %%f
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
@rem Build the resources
|
||||
rc /nologo /fobuild\janet_win.res janet_win.rc
|
||||
|
||||
@rem Link everything to main client
|
||||
%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj build\core_image.obj
|
||||
%JANET_LINK% /out:janet.exe build\janet.obj build\shell.obj build\janet_win.res
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build static library (libjanet.a)
|
||||
%JANET_LINK_STATIC% /out:build\libjanet.lib build\janet.obj
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
echo === Successfully built janet.exe for Windows ===
|
||||
@@ -98,17 +87,18 @@ exit /b 1
|
||||
@echo command prompt.
|
||||
exit /b 0
|
||||
|
||||
@rem Clean build artifacts
|
||||
@rem Clean build artifacts
|
||||
:CLEAN
|
||||
del janet.exe janet.exp janet.lib
|
||||
del *.exe *.lib *.exp
|
||||
rd /s /q build
|
||||
rd /s /q dist
|
||||
exit /b 0
|
||||
|
||||
@rem Run tests
|
||||
:TEST
|
||||
for %%f in (test/suite*.janet) do (
|
||||
janet.exe test\%%f
|
||||
@if errorlevel 1 goto :TESTFAIL
|
||||
@if errorlevel 1 goto TESTFAIL
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
@@ -116,15 +106,61 @@ exit /b 0
|
||||
:DIST
|
||||
mkdir dist
|
||||
janet.exe tools\gendoc.janet > dist\doc.html
|
||||
janet.exe tools\amalg.janet > dist\janet.c
|
||||
janet.exe tools\removecr.janet dist\doc.html
|
||||
janet.exe tools\removecr.janet build\c\janet.c
|
||||
|
||||
copy build\c\janet.c dist\janet.c
|
||||
copy src\mainclient\shell.c dist\shell.c
|
||||
copy janet.exe dist\janet.exe
|
||||
copy LICENSE dist\LICENSE
|
||||
copy README.md dist\README.md
|
||||
|
||||
copy janet.lib dist\janet.lib
|
||||
copy janet.exp dist\janet.exp
|
||||
copy src\include\janet\janet.h dist\janet.h
|
||||
copy tools\cook.janet dist\cook.janet
|
||||
copy tools\highlight.janet dist\highlight.janet
|
||||
|
||||
janet.exe tools\patch-header.janet src\include\janet.h src\conf\janetconf.h build\janet.h
|
||||
copy build\janet.h dist\janet.h
|
||||
copy build\libjanet.lib dist\libjanet.lib
|
||||
|
||||
@rem Create installer
|
||||
janet.exe -e "(->> janet/version (peg/match ''(* :d+ `.` :d+ `.` :d+)) first print)" > build\version.txt
|
||||
janet.exe -e "(print (os/arch))" > build\arch.txt
|
||||
set /p JANET_VERSION= < build\version.txt
|
||||
set /p BUILDARCH= < build\arch.txt
|
||||
echo "JANET_VERSION is %JANET_VERSION%"
|
||||
if defined APPVEYOR_REPO_TAG_NAME (
|
||||
set RELEASE_VERSION=%APPVEYOR_REPO_TAG_NAME%
|
||||
) else (
|
||||
set RELEASE_VERSION=%JANET_VERSION%
|
||||
)
|
||||
if defined CI (
|
||||
set WIXBIN="c:\Program Files (x86)\WiX Toolset v3.11\bin\"
|
||||
) else (
|
||||
set WIXBIN=
|
||||
)
|
||||
%WIXBIN%candle.exe tools\msi\janet.wxs -arch %BUILDARCH% -out build\
|
||||
%WIXBIN%light.exe "-sice:ICE38" -b tools\msi -ext WixUIExtension build\janet.wixobj -out janet-%RELEASE_VERSION%-windows-%BUILDARCH%-installer.msi
|
||||
exit /b 0
|
||||
|
||||
@rem Run the installer. (Installs to the local user with default settings)
|
||||
:INSTALL
|
||||
FOR %%a in (janet-*-windows-*-installer.msi) DO (
|
||||
@echo Running Installer %%a...
|
||||
%%a /QN
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
@rem build, test, dist, install. Useful for local dev.
|
||||
:ALL
|
||||
call %0 build
|
||||
@if errorlevel 1 exit /b 1
|
||||
call %0 test
|
||||
@if errorlevel 1 exit /b 1
|
||||
call %0 dist
|
||||
@if errorlevel 1 exit /b 1
|
||||
call %0 install
|
||||
@if errorlevel 1 exit /b 1
|
||||
@echo Done!
|
||||
exit /b 0
|
||||
|
||||
:TESTFAIL
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
(map keys (keys solutions)))
|
||||
|
||||
(def arr @[2 4 1 3 8 7 -3 -1 12 -5 -8])
|
||||
(print "3sum of " (string/pretty arr) ":")
|
||||
(print (string/pretty (sum3 arr)))
|
||||
(printf "3sum of %P: " arr)
|
||||
(printf "%P\n" (sum3 arr))
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
# Example of dst bytecode assembly
|
||||
|
||||
# Fibonacci sequence, implemented with naive recursion.
|
||||
(def fibasm (asm '{
|
||||
arity 1
|
||||
bytecode [
|
||||
(ltim 1 0 0x2) # $1 = $0 < 2
|
||||
(jmpif 1 :done) # if ($1) goto :done
|
||||
(lds 1) # $1 = self
|
||||
(addim 0 0 -0x1) # $0 = $0 - 1
|
||||
(push 0) # push($0), push argument for next function call
|
||||
(call 2 1) # $2 = call($1)
|
||||
(addim 0 0 -0x1) # $0 = $0 - 1
|
||||
(push 0) # push($0)
|
||||
(call 0 1) # $0 = call($1)
|
||||
(add 0 0 2) # $0 = $0 + $2 (integers)
|
||||
:done
|
||||
(ret 0) # return $0
|
||||
]
|
||||
}))
|
||||
(def fibasm
|
||||
(asm
|
||||
'{:arity 1
|
||||
:bytecode @[(ltim 1 0 0x2) # $1 = $0 < 2
|
||||
(jmpif 1 :done) # if ($1) goto :done
|
||||
(lds 1) # $1 = self
|
||||
(addim 0 0 -0x1) # $0 = $0 - 1
|
||||
(push 0) # push($0), push argument for next function call
|
||||
(call 2 1) # $2 = call($1)
|
||||
(addim 0 0 -0x1) # $0 = $0 - 1
|
||||
(push 0) # push($0)
|
||||
(call 0 1) # $0 = call($1)
|
||||
(add 0 0 2) # $0 = $0 + $2 (integers)
|
||||
:done
|
||||
(ret 0) # return $0
|
||||
]}))
|
||||
|
||||
# Test it
|
||||
|
||||
|
||||
22
examples/async-execute.janet
Normal file
22
examples/async-execute.janet
Normal file
@@ -0,0 +1,22 @@
|
||||
(defn dowork [name n]
|
||||
(print name " starting work...")
|
||||
(os/execute [(dyn :executable) "-e" (string "(os/sleep " n ")")] :p)
|
||||
(print name " finished work!"))
|
||||
|
||||
# Will be done in parallel
|
||||
(print "starting group A")
|
||||
(ev/call dowork "A 2" 2)
|
||||
(ev/call dowork "A 1" 1)
|
||||
(ev/call dowork "A 3" 3)
|
||||
|
||||
(ev/sleep 4)
|
||||
|
||||
# Will also be done in parallel
|
||||
(print "starting group B")
|
||||
(ev/call dowork "B 2" 2)
|
||||
(ev/call dowork "B 1" 1)
|
||||
(ev/call dowork "B 3" 3)
|
||||
|
||||
(ev/sleep 4)
|
||||
|
||||
(print "all work done")
|
||||
15
examples/channel.janet
Normal file
15
examples/channel.janet
Normal file
@@ -0,0 +1,15 @@
|
||||
(def c (ev/chan 4))
|
||||
|
||||
(defn writer []
|
||||
(for i 0 10
|
||||
(ev/sleep 0.1)
|
||||
(print "writer giving item " i "...")
|
||||
(ev/give c (string "item " i))))
|
||||
|
||||
(defn reader [name]
|
||||
(forever
|
||||
(print "reader " name " got " (ev/take c))))
|
||||
|
||||
(ev/call writer)
|
||||
(each letter [:a :b :c :d :e :f :g]
|
||||
(ev/call reader letter))
|
||||
11
examples/debug.janet
Normal file
11
examples/debug.janet
Normal file
@@ -0,0 +1,11 @@
|
||||
# Load this file and run (myfn) to see the debugger
|
||||
|
||||
(defn myfn
|
||||
[]
|
||||
(debug)
|
||||
(for i 0 10 (print i)))
|
||||
|
||||
(debug/fbreak myfn 3)
|
||||
|
||||
# Enable debugging in repl with
|
||||
# (setdyn :debug true)
|
||||
151
examples/debugger.janet
Normal file
151
examples/debugger.janet
Normal file
@@ -0,0 +1,151 @@
|
||||
###
|
||||
### A useful debugger library for Janet. Should be used
|
||||
### inside a debug repl. This has been moved into the core.
|
||||
###
|
||||
|
||||
(defn .fiber
|
||||
"Get the current fiber being debugged."
|
||||
[]
|
||||
(dyn :fiber))
|
||||
|
||||
(defn .stack
|
||||
"Print the current fiber stack"
|
||||
[]
|
||||
(print)
|
||||
(with-dyns [:err-color false] (debug/stacktrace (.fiber) ""))
|
||||
(print))
|
||||
|
||||
(defn .frame
|
||||
"Show a stack frame"
|
||||
[&opt n]
|
||||
(def stack (debug/stack (.fiber)))
|
||||
(in stack (or n 0)))
|
||||
|
||||
(defn .fn
|
||||
"Get the current function"
|
||||
[&opt n]
|
||||
(in (.frame n) :function))
|
||||
|
||||
(defn .slots
|
||||
"Get an array of slots in a stack frame"
|
||||
[&opt n]
|
||||
(in (.frame n) :slots))
|
||||
|
||||
(defn .slot
|
||||
"Get the value of the nth slot."
|
||||
[&opt nth frame-idx]
|
||||
(in (.slots frame-idx) (or nth 0)))
|
||||
|
||||
(defn .quit
|
||||
"Resume (dyn :fiber) with the value passed to it after exiting the debugger."
|
||||
[&opt val]
|
||||
(setdyn :exit true)
|
||||
(setdyn :resume-value val)
|
||||
nil)
|
||||
|
||||
(defn .disasm
|
||||
"Gets the assembly for the current function."
|
||||
[&opt n]
|
||||
(def frame (.frame n))
|
||||
(def func (frame :function))
|
||||
(disasm func))
|
||||
|
||||
(defn .bytecode
|
||||
"Get the bytecode for the current function."
|
||||
[&opt n]
|
||||
((.disasm n) 'bytecode))
|
||||
|
||||
(defn .ppasm
|
||||
"Pretty prints the assembly for the current function"
|
||||
[&opt n]
|
||||
(def frame (.frame n))
|
||||
(def func (frame :function))
|
||||
(def dasm (disasm func))
|
||||
(def bytecode (dasm 'bytecode))
|
||||
(def pc (frame :pc))
|
||||
(def sourcemap (dasm 'sourcemap))
|
||||
(var last-loc [-2 -2])
|
||||
(print "\n function: " (dasm 'name) " [" (in dasm 'source "") "]")
|
||||
(when-let [constants (dasm 'constants)]
|
||||
(printf " constants: %.4Q" constants))
|
||||
(printf " slots: %.4Q\n" (frame :slots))
|
||||
(def padding (string/repeat " " 20))
|
||||
(loop [i :range [0 (length bytecode)]
|
||||
:let [instr (bytecode i)]]
|
||||
(prin (if (= (tuple/type instr) :brackets) "*" " "))
|
||||
(prin (if (= i pc) "> " " "))
|
||||
(prinf "\e[33m%.20s\e[0m" (string (string/join (map string instr) " ") padding))
|
||||
(when sourcemap
|
||||
(let [[sl sc] (sourcemap i)
|
||||
loc [sl sc]]
|
||||
(when (not= loc last-loc)
|
||||
(set last-loc loc)
|
||||
(prin " # line " sl ", column " sc))))
|
||||
(print))
|
||||
(print))
|
||||
|
||||
(defn .source
|
||||
"Show the source code for the function being debugged."
|
||||
[&opt n]
|
||||
(def frame (.frame n))
|
||||
(def s (frame :source))
|
||||
(def all-source (slurp s))
|
||||
(print "\n\e[33m" all-source "\e[0m\n"))
|
||||
|
||||
(defn .breakall
|
||||
"Set breakpoints on all instructions in the current function."
|
||||
[&opt n]
|
||||
(def fun (.fn n))
|
||||
(def bytecode (.bytecode n))
|
||||
(for i 0 (length bytecode)
|
||||
(debug/fbreak fun i))
|
||||
(print "Set " (length bytecode) " breakpoints in " fun))
|
||||
|
||||
(defn .clearall
|
||||
"Clear all breakpoints on the current function."
|
||||
[&opt n]
|
||||
(def fun (.fn n))
|
||||
(def bytecode (.bytecode n))
|
||||
(for i 0 (length bytecode)
|
||||
(debug/unfbreak fun i))
|
||||
(print "Cleared " (length bytecode) " breakpoints in " fun))
|
||||
|
||||
(defn .break
|
||||
"Set breakpoint at the current pc."
|
||||
[]
|
||||
(def frame (.frame))
|
||||
(def fun (frame :function))
|
||||
(def pc (frame :pc))
|
||||
(debug/fbreak fun pc)
|
||||
(print "Set breakpoint in " fun " at pc=" pc))
|
||||
|
||||
(defn .clear
|
||||
"Clear the current breakpoint"
|
||||
[]
|
||||
(def frame (.frame))
|
||||
(def fun (frame :function))
|
||||
(def pc (frame :pc))
|
||||
(debug/unfbreak fun pc)
|
||||
(print "Cleared breakpoint in " fun " at pc=" pc))
|
||||
|
||||
(defn .next
|
||||
"Go to the next breakpoint."
|
||||
[&opt n]
|
||||
(var res nil)
|
||||
(for i 0 (or n 1)
|
||||
(set res (resume (.fiber))))
|
||||
res)
|
||||
|
||||
(defn .nextc
|
||||
"Go to the next breakpoint, clearing the current breakpoint."
|
||||
[&opt n]
|
||||
(.clear)
|
||||
(.next n))
|
||||
|
||||
(defn .step
|
||||
"Execute the next n instructions."
|
||||
[&opt n]
|
||||
(var res nil)
|
||||
(for i 0 (or n 1)
|
||||
(set res (debug/step (.fiber))))
|
||||
res)
|
||||
5
examples/echoclient.janet
Normal file
5
examples/echoclient.janet
Normal file
@@ -0,0 +1,5 @@
|
||||
(with [conn (net/connect "127.0.0.1" 8000)]
|
||||
(print "writing abcdefg...")
|
||||
(:write conn "abcdefg")
|
||||
(print "reading...")
|
||||
(printf "got: %v" (:read conn 1024)))
|
||||
15
examples/echoserve.janet
Normal file
15
examples/echoserve.janet
Normal file
@@ -0,0 +1,15 @@
|
||||
(defn handler
|
||||
"Simple handler for connections."
|
||||
[stream]
|
||||
(defer (:close stream)
|
||||
(def id (gensym))
|
||||
(def b @"")
|
||||
(print "Connection " id "!")
|
||||
(while (:read stream 1024 b)
|
||||
(printf " %v -> %v" id b)
|
||||
(:write stream b)
|
||||
(buffer/clear b))
|
||||
(printf "Done %v!" id)
|
||||
(ev/sleep 0.5)))
|
||||
|
||||
(net/server "127.0.0.1" "8000" handler)
|
||||
45
examples/evlocks.janet
Normal file
45
examples/evlocks.janet
Normal file
@@ -0,0 +1,45 @@
|
||||
(defn sleep
|
||||
"Sleep the entire thread, not just a single fiber."
|
||||
[n]
|
||||
(os/sleep (* 0.1 n)))
|
||||
|
||||
(defn work [lock n]
|
||||
(ev/acquire-lock lock)
|
||||
(print "working " n "...")
|
||||
(sleep n)
|
||||
(print "done working...")
|
||||
(ev/release-lock lock))
|
||||
|
||||
(defn reader
|
||||
[rwlock n]
|
||||
(ev/acquire-rlock rwlock)
|
||||
(print "reading " n "...")
|
||||
(sleep n)
|
||||
(print "done reading " n "...")
|
||||
(ev/release-rlock rwlock))
|
||||
|
||||
(defn writer
|
||||
[rwlock n]
|
||||
(ev/acquire-wlock rwlock)
|
||||
(print "writing " n "...")
|
||||
(sleep n)
|
||||
(print "done writing...")
|
||||
(ev/release-wlock rwlock))
|
||||
|
||||
(defn test-lock
|
||||
[]
|
||||
(def lock (ev/lock))
|
||||
(for i 3 7
|
||||
(ev/spawn-thread
|
||||
(work lock i))))
|
||||
|
||||
(defn test-rwlock
|
||||
[]
|
||||
(def rwlock (ev/rwlock))
|
||||
(for i 0 20
|
||||
(if (> 0.1 (math/random))
|
||||
(ev/spawn-thread (writer rwlock i))
|
||||
(ev/spawn-thread (reader rwlock i)))))
|
||||
|
||||
(test-rwlock)
|
||||
(test-lock)
|
||||
22
examples/evsleep.janet
Normal file
22
examples/evsleep.janet
Normal file
@@ -0,0 +1,22 @@
|
||||
(defn worker
|
||||
"Run for a number of iterations."
|
||||
[name iterations]
|
||||
(for i 0 iterations
|
||||
(ev/sleep 1)
|
||||
(print "worker " name " iteration " i)))
|
||||
|
||||
(ev/call worker :a 10)
|
||||
(ev/sleep 0.2)
|
||||
(ev/call worker :b 5)
|
||||
(ev/sleep 0.3)
|
||||
(ev/call worker :c 12)
|
||||
|
||||
(defn worker2
|
||||
[name]
|
||||
(repeat 10
|
||||
(ev/sleep 0.2)
|
||||
(print name " working")))
|
||||
|
||||
(ev/go worker2 :bob)
|
||||
(ev/go worker2 :joe)
|
||||
(ev/go worker2 :sally)
|
||||
71
examples/ffi/gtk.janet
Normal file
71
examples/ffi/gtk.janet
Normal file
@@ -0,0 +1,71 @@
|
||||
# :lazy true needed for jpm quickbin
|
||||
# lazily loads library on first function use
|
||||
# so the `main` function
|
||||
# can be marshalled.
|
||||
(ffi/context "/usr/lib/libgtk-3.so" :lazy true)
|
||||
|
||||
(ffi/defbind
|
||||
gtk-application-new :ptr
|
||||
"Add docstrings as needed."
|
||||
[title :string flags :uint])
|
||||
|
||||
(ffi/defbind
|
||||
g-signal-connect-data :ulong
|
||||
[a :ptr b :ptr c :ptr d :ptr e :ptr f :int])
|
||||
|
||||
(ffi/defbind
|
||||
g-application-run :int
|
||||
[app :ptr argc :int argv :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-application-window-new :ptr
|
||||
[a :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-button-new-with-label :ptr
|
||||
[a :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-container-add :void
|
||||
[a :ptr b :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-widget-show-all :void
|
||||
[a :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-button-set-label :void
|
||||
[a :ptr b :ptr])
|
||||
|
||||
(def cb (delay (ffi/trampoline :default)))
|
||||
|
||||
(defn ffi/array
|
||||
``Convert a janet array to a buffer that can be passed to FFI functions.
|
||||
For example, to create an array of type `char *` (array of c strings), one
|
||||
could use `(ffi/array ["hello" "world"] :ptr)`. One needs to be careful that
|
||||
array elements are not garbage collected though - the GC can't follow references
|
||||
inside an arbitrary byte buffer.``
|
||||
[arr ctype &opt buf]
|
||||
(default buf @"")
|
||||
(each el arr
|
||||
(ffi/write ctype el buf))
|
||||
buf)
|
||||
|
||||
(defn on-active
|
||||
[app]
|
||||
(def window (gtk-application-window-new app))
|
||||
(def btn (gtk-button-new-with-label "Click Me!"))
|
||||
(g-signal-connect-data btn "clicked" (cb)
|
||||
(fn [btn] (gtk-button-set-label btn "Hello World"))
|
||||
nil 1)
|
||||
(gtk-container-add window btn)
|
||||
(gtk-widget-show-all window))
|
||||
|
||||
(defn main
|
||||
[&]
|
||||
(def app (gtk-application-new "org.janet-lang.example.HelloApp" 0))
|
||||
(g-signal-connect-data app "activate" (cb) on-active nil 1)
|
||||
# manually build an array with ffi/write
|
||||
# - we are responsible for preventing gc when the arg array is used
|
||||
(def argv (ffi/array (dyn *args*) :string))
|
||||
(g-application-run app (length (dyn *args*)) argv))
|
||||
205
examples/ffi/so.c
Normal file
205
examples/ffi/so.c
Normal file
@@ -0,0 +1,205 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXPORTER __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORTER
|
||||
#endif
|
||||
|
||||
/* Structs */
|
||||
|
||||
typedef struct {
|
||||
int a, b;
|
||||
float c, d;
|
||||
} Split;
|
||||
|
||||
typedef struct {
|
||||
float c, d;
|
||||
int a, b;
|
||||
} SplitFlip;
|
||||
|
||||
typedef struct {
|
||||
int u, v, w, x, y, z;
|
||||
} SixInts;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} intint;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} intintint;
|
||||
|
||||
typedef struct {
|
||||
int64_t a;
|
||||
int64_t b;
|
||||
int64_t c;
|
||||
} big;
|
||||
|
||||
/* Functions */
|
||||
|
||||
EXPORTER
|
||||
int int_fn(int a, int b) {
|
||||
return (a << 2) + b;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double my_fn(int64_t a, int64_t b, const char *x) {
|
||||
return (double)(a + b) + 0.5 + strlen(x);
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_fn(double x, double y, double z) {
|
||||
return (x + y) * z * 3;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_many(double x, double y, double z, double w, double a, double b) {
|
||||
return x + y + z + w + a + b;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_lots(
|
||||
double a,
|
||||
double b,
|
||||
double c,
|
||||
double d,
|
||||
double e,
|
||||
double f,
|
||||
double g,
|
||||
double h,
|
||||
double i,
|
||||
double j) {
|
||||
return i + j;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_lots_2(
|
||||
double a,
|
||||
double b,
|
||||
double c,
|
||||
double d,
|
||||
double e,
|
||||
double f,
|
||||
double g,
|
||||
double h,
|
||||
double i,
|
||||
double j) {
|
||||
return a +
|
||||
10.0 * b +
|
||||
100.0 * c +
|
||||
1000.0 * d +
|
||||
10000.0 * e +
|
||||
100000.0 * f +
|
||||
1000000.0 * g +
|
||||
10000000.0 * h +
|
||||
100000000.0 * i +
|
||||
1000000000.0 * j;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double float_fn(float x, float y, float z) {
|
||||
return (x + y) * z;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int intint_fn(double x, intint ii) {
|
||||
printf("double: %g\n", x);
|
||||
return ii.a + ii.b;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int intintint_fn(double x, intintint iii) {
|
||||
printf("double: %g\n", x);
|
||||
return iii.a + iii.b + iii.c;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
intint return_struct(int i) {
|
||||
intint ret;
|
||||
ret.a = i;
|
||||
ret.b = i * i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
big struct_big(int i, double d) {
|
||||
big ret;
|
||||
ret.a = i;
|
||||
ret.b = (int64_t) d;
|
||||
ret.c = ret.a + ret.b + 1000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
void void_fn(void) {
|
||||
printf("void fn ran\n");
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
void void_fn_2(double y) {
|
||||
printf("y = %f\n", y);
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
void void_ret_fn(int x) {
|
||||
printf("void fn ran: %d\n", x);
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int intintint_fn_2(intintint iii, int i) {
|
||||
fprintf(stderr, "iii.a = %d, iii.b = %d, iii.c = %d, i = %d\n", iii.a, iii.b, iii.c, i);
|
||||
return i * (iii.a + iii.b + iii.c);
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
float split_fn(Split s) {
|
||||
return s.a * s.c + s.b * s.d;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
float split_flip_fn(SplitFlip s) {
|
||||
return s.a * s.c + s.b * s.d;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
Split split_ret_fn(int x, float y) {
|
||||
Split ret;
|
||||
ret.a = x;
|
||||
ret.b = x;
|
||||
ret.c = y;
|
||||
ret.d = y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
SplitFlip split_flip_ret_fn(int x, float y) {
|
||||
SplitFlip ret;
|
||||
ret.a = x;
|
||||
ret.b = x;
|
||||
ret.c = y;
|
||||
ret.d = y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
SixInts sixints_fn(void) {
|
||||
return (SixInts) {
|
||||
6666, 1111, 2222, 3333, 4444, 5555
|
||||
};
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int sixints_fn_2(int x, SixInts s) {
|
||||
return x + s.u + s.v + s.w + s.x + s.y + s.z;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int sixints_fn_3(SixInts s, int x) {
|
||||
return x + s.u + s.v + s.w + s.x + s.y + s.z;
|
||||
}
|
||||
134
examples/ffi/test.janet
Normal file
134
examples/ffi/test.janet
Normal file
@@ -0,0 +1,134 @@
|
||||
#
|
||||
# Simple FFI test script that tests against a simple shared object
|
||||
#
|
||||
|
||||
(def is-windows (= :windows (os/which)))
|
||||
(def ffi/loc (string "examples/ffi/so." (if is-windows "dll" "so")))
|
||||
(def ffi/source-loc "examples/ffi/so.c")
|
||||
|
||||
(if is-windows
|
||||
(os/execute ["cl.exe" "/nologo" "/LD" ffi/source-loc "/link" "/DLL" (string "/OUT:" ffi/loc)] :px)
|
||||
(os/execute ["cc" ffi/source-loc "-shared" "-o" ffi/loc] :px))
|
||||
|
||||
(ffi/context ffi/loc)
|
||||
|
||||
(def intintint (ffi/struct :int :int :int))
|
||||
(def big (ffi/struct :s64 :s64 :s64))
|
||||
(def split (ffi/struct :int :int :float :float))
|
||||
(def split-flip (ffi/struct :float :float :int :int))
|
||||
(def six-ints (ffi/struct :int :int :int :int :int :int))
|
||||
|
||||
(ffi/defbind int-fn :int [a :int b :int])
|
||||
(ffi/defbind double-fn :double [a :double b :double c :double])
|
||||
(ffi/defbind double-many :double
|
||||
[x :double y :double z :double w :double a :double b :double])
|
||||
(ffi/defbind double-lots :double
|
||||
[a :double b :double c :double d :double e :double f :double g :double h :double i :double j :double])
|
||||
(ffi/defbind float-fn :double
|
||||
[x :float y :float z :float])
|
||||
(ffi/defbind intint-fn :int
|
||||
[x :double ii [:int :int]])
|
||||
(ffi/defbind return-struct [:int :int]
|
||||
[i :int])
|
||||
(ffi/defbind intintint-fn :int
|
||||
[x :double iii intintint])
|
||||
(ffi/defbind struct-big big
|
||||
[i :int d :double])
|
||||
(ffi/defbind void-fn :void [])
|
||||
(ffi/defbind double-lots-2 :double
|
||||
[a :double
|
||||
b :double
|
||||
c :double
|
||||
d :double
|
||||
e :double
|
||||
f :double
|
||||
g :double
|
||||
h :double
|
||||
i :double
|
||||
j :double])
|
||||
(ffi/defbind void-fn-2 :void [y :double])
|
||||
(ffi/defbind intintint-fn-2 :int [iii intintint i :int])
|
||||
(ffi/defbind split-fn :float [s split])
|
||||
(ffi/defbind split-flip-fn :float [s split-flip])
|
||||
(ffi/defbind split-ret-fn split [x :int y :float])
|
||||
(ffi/defbind split-flip-ret-fn split-flip [x :int y :float])
|
||||
(ffi/defbind sixints-fn six-ints [])
|
||||
(ffi/defbind sixints-fn-2 :int [x :int s six-ints])
|
||||
(ffi/defbind sixints-fn-3 :int [s six-ints x :int])
|
||||
|
||||
#
|
||||
# Struct reading and writing
|
||||
#
|
||||
|
||||
(defn check-round-trip
|
||||
[t value]
|
||||
(def buf (ffi/write t value))
|
||||
(def same-value (ffi/read t buf))
|
||||
(assert (deep= value same-value)
|
||||
(string/format "round trip %j (got %j)" value same-value)))
|
||||
|
||||
(check-round-trip :bool true)
|
||||
(check-round-trip :bool false)
|
||||
(check-round-trip :void nil)
|
||||
(check-round-trip :void nil)
|
||||
(check-round-trip :s8 10)
|
||||
(check-round-trip :s8 0)
|
||||
(check-round-trip :s8 -10)
|
||||
(check-round-trip :u8 10)
|
||||
(check-round-trip :u8 0)
|
||||
(check-round-trip :s16 10)
|
||||
(check-round-trip :s16 0)
|
||||
(check-round-trip :s16 -12312)
|
||||
(check-round-trip :u16 10)
|
||||
(check-round-trip :u16 0)
|
||||
(check-round-trip :u32 0)
|
||||
(check-round-trip :u32 10)
|
||||
(check-round-trip :u32 0xFFFF7777)
|
||||
(check-round-trip :s32 0x7FFF7777)
|
||||
(check-round-trip :s32 0)
|
||||
(check-round-trip :s32 -1234567)
|
||||
|
||||
(def s (ffi/struct :s8 :s8 :s8 :float))
|
||||
(check-round-trip s [1 3 5 123.5])
|
||||
(check-round-trip s [-1 -3 -5 -123.5])
|
||||
|
||||
#
|
||||
# Call functions
|
||||
#
|
||||
|
||||
(tracev (sixints-fn))
|
||||
(tracev (sixints-fn-2 100 [1 2 3 4 5 6]))
|
||||
(tracev (sixints-fn-3 [1 2 3 4 5 6] 200))
|
||||
(tracev (split-ret-fn 10 12))
|
||||
(tracev (split-flip-ret-fn 10 12))
|
||||
(tracev (split-flip-ret-fn 12 10))
|
||||
(tracev (intintint-fn-2 [10 20 30] 3))
|
||||
(tracev (split-fn [5 6 1.2 3.4]))
|
||||
(tracev (void-fn-2 10.3))
|
||||
(tracev (double-many 1 2 3 4 5 6))
|
||||
(tracev (string/format "%.17g" (double-many 1 2 3 4 5 6)))
|
||||
(tracev (type (double-many 1 2 3 4 5 6)))
|
||||
(tracev (double-lots-2 0 1 2 3 4 5 6 7 8 9))
|
||||
(tracev (void-fn))
|
||||
(tracev (int-fn 10 20))
|
||||
(tracev (double-fn 1.5 2.5 3.5))
|
||||
(tracev (double-lots 1 2 3 4 5 6 7 8 9 10))
|
||||
(tracev (float-fn 8 4 17))
|
||||
(tracev (intint-fn 123.456 [10 20]))
|
||||
(tracev (intintint-fn 123.456 [10 20 30]))
|
||||
(tracev (return-struct 42))
|
||||
(tracev (double-lots 1 2 3 4 5 6 700 800 9 10))
|
||||
(tracev (struct-big 11 99.5))
|
||||
|
||||
(assert (= [10 10 12 12] (split-ret-fn 10 12)))
|
||||
(assert (= [12 12 10 10] (split-flip-ret-fn 10 12)))
|
||||
(assert (= 183 (intintint-fn-2 [10 20 31] 3)))
|
||||
(assert (= 264 (math/round (* 10 (split-fn [5 6 1.2 3.4])))))
|
||||
(assert (= 9876543210 (double-lots-2 0 1 2 3 4 5 6 7 8 9)))
|
||||
(assert (= 60 (int-fn 10 20)))
|
||||
(assert (= 42 (double-fn 1.5 2.5 3.5)))
|
||||
(assert (= 21 (math/round (double-many 1 2 3 4 5 6.01))))
|
||||
(assert (= 19 (double-lots 1 2 3 4 5 6 7 8 9 10)))
|
||||
(assert (= 204 (float-fn 8 4 17)))
|
||||
|
||||
(print "Done.")
|
||||
7
examples/ffi/win32.janet
Normal file
7
examples/ffi/win32.janet
Normal file
@@ -0,0 +1,7 @@
|
||||
(ffi/context "user32.dll")
|
||||
|
||||
(ffi/defbind MessageBoxA :int
|
||||
[w :ptr text :string cap :string typ :int])
|
||||
|
||||
(MessageBoxA nil "Hello, World!" "Test" 0)
|
||||
|
||||
19
examples/iterate-fiber.janet
Normal file
19
examples/iterate-fiber.janet
Normal file
@@ -0,0 +1,19 @@
|
||||
(def f
|
||||
(coro
|
||||
(for i 0 10
|
||||
(yield (string "yield " i))
|
||||
(os/sleep 0))))
|
||||
|
||||
(print "simple yielding")
|
||||
(each item f (print "got: " item ", now " (fiber/status f)))
|
||||
|
||||
(def f
|
||||
(coro
|
||||
(for i 0 10
|
||||
(yield (string "yield " i))
|
||||
(ev/sleep 0))))
|
||||
|
||||
(print "complex yielding")
|
||||
(each item f (print "got: " item ", now " (fiber/status f)))
|
||||
|
||||
(print (fiber/status f))
|
||||
BIN
examples/jitfn/hello.bin
Normal file
BIN
examples/jitfn/hello.bin
Normal file
Binary file not shown.
17
examples/jitfn/hello.nasm
Normal file
17
examples/jitfn/hello.nasm
Normal file
@@ -0,0 +1,17 @@
|
||||
BITS 64
|
||||
|
||||
;;;
|
||||
;;; Code
|
||||
;;;
|
||||
mov rax, 1 ; write(
|
||||
mov rdi, 1 ; STDOUT_FILENO,
|
||||
lea rsi, [rel msg] ; msg,
|
||||
mov rdx, msglen ; sizeof(msg)
|
||||
syscall ; );
|
||||
ret ; return;
|
||||
|
||||
;;;
|
||||
;;; Constants
|
||||
;;;
|
||||
msg: db "Hello, world!", 10
|
||||
msglen: equ $ - msg
|
||||
13
examples/jitfn/jitfn.janet
Normal file
13
examples/jitfn/jitfn.janet
Normal file
@@ -0,0 +1,13 @@
|
||||
###
|
||||
### Relies on NASM being installed to assemble code.
|
||||
### Only works on x86-64 Linux.
|
||||
###
|
||||
### Before running, compile hello.nasm to hello.bin with
|
||||
### $ nasm hello.nasm -o hello.bin
|
||||
|
||||
(def bin (slurp "hello.bin"))
|
||||
(def f (ffi/jitfn bin))
|
||||
(def signature (ffi/signature :default :void))
|
||||
(ffi/call f signature)
|
||||
(print "called a jitted function with FFI!")
|
||||
(print "machine code: " (describe (string/slice f)))
|
||||
@@ -4,11 +4,11 @@
|
||||
(seq [x :range [-1 2]
|
||||
y :range [-1 2]
|
||||
:when (not (and (zero? x) (zero? y)))]
|
||||
(tuple x y)))
|
||||
[x y]))
|
||||
|
||||
(defn- neighbors
|
||||
[[x y]]
|
||||
(map (fn [[x1 y1]] (tuple (+ x x1) (+ y y1))) window))
|
||||
(map (fn [[x1 y1]] [(+ x x1) (+ y y1)]) window))
|
||||
|
||||
(defn tick
|
||||
"Get the next state in the Game Of Life."
|
||||
@@ -28,7 +28,7 @@
|
||||
(loop [x :range [x1 (+ 1 x2)]
|
||||
:after (print)
|
||||
y :range [y1 (+ 1 y2)]]
|
||||
(file/write stdout (if (get cellset (tuple x y)) "X " ". ")))
|
||||
(file/write stdout (if (get cellset [x y]) "X " ". ")))
|
||||
(print))
|
||||
|
||||
#
|
||||
|
||||
2
examples/lineloop.janet
Normal file
2
examples/lineloop.janet
Normal file
@@ -0,0 +1,2 @@
|
||||
(while (not (empty? (def line (getline))))
|
||||
(prin "line: " line))
|
||||
30
examples/marshal-stress.janet
Normal file
30
examples/marshal-stress.janet
Normal file
@@ -0,0 +1,30 @@
|
||||
(defn init-db [c]
|
||||
(def res @{:clients @{}})
|
||||
(var i 0)
|
||||
(repeat c
|
||||
(def n (string "client" i))
|
||||
(put-in res [:clients n] @{:name n :projects @{}})
|
||||
(++ i)
|
||||
(repeat c
|
||||
(def pn (string "project" i))
|
||||
(put-in res [:clients n :projects pn] @{:name pn})
|
||||
(++ i)
|
||||
(repeat c
|
||||
(def tn (string "task" i))
|
||||
(put-in res [:clients n :projects pn :tasks tn] @{:name pn})
|
||||
(++ i))))
|
||||
res)
|
||||
|
||||
(loop [c :range [30 80 1]]
|
||||
(var s (os/clock))
|
||||
(print "Marshal DB with " c " clients, "
|
||||
(* c c) " projects and "
|
||||
(* c c c) " tasks. "
|
||||
"Total " (+ (* c c c) (* c c) c) " tables")
|
||||
(def buf (marshal (init-db c) @{} @""))
|
||||
(print "Buffer is " (length buf) " bytes")
|
||||
(print "Duration " (- (os/clock) s))
|
||||
(set s (os/clock))
|
||||
(gccollect)
|
||||
(print "Collected garbage in " (- (os/clock) s)))
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
# of the triangle to the leaves of the triangle.
|
||||
|
||||
(defn myfold [xs ys]
|
||||
(let [xs1 (tuple/prepend xs 0)
|
||||
xs2 (tuple/append xs 0)
|
||||
m1 (map + xs1 ys)
|
||||
m2 (map + xs2 ys)]
|
||||
(let [m1 (map + [;xs 0] ys)
|
||||
m2 (map + [0 ;xs] ys)]
|
||||
(map max m1 m2)))
|
||||
|
||||
(defn maxpath [t]
|
||||
|
||||
1
examples/numarray/.gitignore
vendored
Normal file
1
examples/numarray/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -1,29 +1,29 @@
|
||||
#include <stdlib.h>
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
|
||||
typedef struct {
|
||||
double * data;
|
||||
double *data;
|
||||
size_t size;
|
||||
} num_array;
|
||||
|
||||
static num_array * num_array_init(num_array * array,size_t size) {
|
||||
array->data=(double *)calloc(size,sizeof(double));
|
||||
array->size=size;
|
||||
static num_array *num_array_init(num_array *array, size_t size) {
|
||||
array->data = (double *)janet_calloc(size, sizeof(double));
|
||||
array->size = size;
|
||||
return array;
|
||||
}
|
||||
|
||||
static void num_array_deinit(num_array * array) {
|
||||
free(array->data);
|
||||
static void num_array_deinit(num_array *array) {
|
||||
janet_free(array->data);
|
||||
}
|
||||
|
||||
static int num_array_gc(void *p, size_t s) {
|
||||
(void) s;
|
||||
num_array * array=(num_array *)p;
|
||||
num_array *array = (num_array *)p;
|
||||
num_array_deinit(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Janet num_array_get(void *p, Janet key);
|
||||
int num_array_get(void *p, Janet key, Janet *out);
|
||||
void num_array_put(void *p, Janet key, Janet value);
|
||||
|
||||
static const JanetAbstractType num_array_type = {
|
||||
@@ -31,83 +31,97 @@ static const JanetAbstractType num_array_type = {
|
||||
num_array_gc,
|
||||
NULL,
|
||||
num_array_get,
|
||||
num_array_put
|
||||
num_array_put,
|
||||
JANET_ATEND_PUT
|
||||
};
|
||||
|
||||
static Janet num_array_new(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t size=janet_getinteger(argv,0);
|
||||
num_array * array = (num_array *)janet_abstract(&num_array_type,sizeof(num_array));
|
||||
num_array_init(array,size);
|
||||
int32_t size = janet_getinteger(argv, 0);
|
||||
num_array *array = (num_array *)janet_abstract(&num_array_type, sizeof(num_array));
|
||||
num_array_init(array, size);
|
||||
return janet_wrap_abstract(array);
|
||||
}
|
||||
|
||||
static Janet num_array_scale(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
num_array * array = (num_array *)janet_getabstract(argv,0,&num_array_type);
|
||||
double factor = janet_getnumber(argv,1);
|
||||
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
|
||||
double factor = janet_getnumber(argv, 1);
|
||||
size_t i;
|
||||
for (i=0;i<array->size;i++) {
|
||||
array->data[i]*=factor;
|
||||
for (i = 0; i < array->size; i++) {
|
||||
array->data[i] *= factor;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet num_array_sum(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
num_array * array = (num_array *)janet_getabstract(argv,0,&num_array_type);
|
||||
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
|
||||
double sum = 0;
|
||||
for (size_t i=0;i<array->size;i++) sum+=array->data[i];
|
||||
for (size_t i = 0; i < array->size; i++) sum += array->data[i];
|
||||
return janet_wrap_number(sum);
|
||||
}
|
||||
|
||||
void num_array_put(void *p, Janet key, Janet value) {
|
||||
size_t index;
|
||||
num_array * array=(num_array *)p;
|
||||
num_array *array = (num_array *)p;
|
||||
if (!janet_checkint(key))
|
||||
janet_panic("expected integer key");
|
||||
if (!janet_checktype(value,JANET_NUMBER))
|
||||
if (!janet_checktype(value, JANET_NUMBER))
|
||||
janet_panic("expected number value");
|
||||
|
||||
index = (size_t)janet_unwrap_integer(key);
|
||||
if (index < array->size) {
|
||||
array->data[index]=janet_unwrap_number(value);
|
||||
array->data[index] = janet_unwrap_number(value);
|
||||
}
|
||||
}
|
||||
|
||||
static Janet num_array_length(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
|
||||
return janet_wrap_number(array->size);
|
||||
}
|
||||
|
||||
static const JanetMethod methods[] = {
|
||||
{"scale", num_array_scale},
|
||||
{"sum", num_array_sum},
|
||||
{"length", num_array_length},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
Janet num_array_get(void *p, Janet key) {
|
||||
int num_array_get(void *p, Janet key, Janet *out) {
|
||||
size_t index;
|
||||
Janet value;
|
||||
num_array * array=(num_array *)p;
|
||||
num_array *array = (num_array *)p;
|
||||
if (janet_checktype(key, JANET_KEYWORD))
|
||||
return janet_getmethod(janet_unwrap_keyword(key), methods);
|
||||
return janet_getmethod(janet_unwrap_keyword(key), methods, out);
|
||||
if (!janet_checkint(key))
|
||||
janet_panic("expected integer key");
|
||||
index = (size_t)janet_unwrap_integer(key);
|
||||
if (index >= array->size) {
|
||||
value = janet_wrap_nil();
|
||||
return 0;
|
||||
} else {
|
||||
value = janet_wrap_number(array->data[index]);
|
||||
*out = janet_wrap_number(array->data[index]);
|
||||
}
|
||||
return value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"numarray/new", num_array_new,
|
||||
{
|
||||
"new", num_array_new,
|
||||
"(numarray/new size)\n\n"
|
||||
"Create new numarray"
|
||||
"Create new numarray"
|
||||
},
|
||||
{"numarray/scale", num_array_scale,
|
||||
{
|
||||
"scale", num_array_scale,
|
||||
"(numarray/scale numarray factor)\n\n"
|
||||
"scale numarray by factor"
|
||||
"scale numarray by factor"
|
||||
},
|
||||
{NULL,NULL,NULL}
|
||||
{
|
||||
"sum", num_array_sum,
|
||||
"(numarray/sum numarray)\n\n"
|
||||
"sums numarray"
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
JANET_MODULE_ENTRY(JanetTable *env) {
|
||||
|
||||
7
examples/numarray/project.janet
Normal file
7
examples/numarray/project.janet
Normal file
@@ -0,0 +1,7 @@
|
||||
(declare-project
|
||||
:name "numarray"
|
||||
:description "Example c lib with abstract type")
|
||||
|
||||
(declare-native
|
||||
:name "numarray"
|
||||
:source @["numarray.c"])
|
||||
@@ -1,10 +1,4 @@
|
||||
(import cook)
|
||||
|
||||
(cook/make-native
|
||||
:name "numarray"
|
||||
:source @["numarray.c"])
|
||||
|
||||
(import build/numarray :prefix "")
|
||||
(import /build/numarray)
|
||||
|
||||
(def a (numarray/new 30))
|
||||
(print (get a 20))
|
||||
@@ -13,4 +13,4 @@
|
||||
(if isprime? (array/push list i)))
|
||||
list)
|
||||
|
||||
(print (string/pretty (primes 100)))
|
||||
(pp (primes 100))
|
||||
|
||||
11
examples/rtest.janet
Normal file
11
examples/rtest.janet
Normal file
@@ -0,0 +1,11 @@
|
||||
# How random is the RNG really?
|
||||
|
||||
(def counts (seq [_ :range [0 100]] 0))
|
||||
|
||||
(for i 0 1000000
|
||||
(let [x (math/random)
|
||||
intrange (math/floor (* 100 x))
|
||||
oldcount (counts intrange)]
|
||||
(put counts intrange (if oldcount (+ 1 oldcount) 1))))
|
||||
|
||||
(pp counts)
|
||||
23
examples/select.janet
Normal file
23
examples/select.janet
Normal file
@@ -0,0 +1,23 @@
|
||||
(def channels
|
||||
(seq [:repeat 5] (ev/chan 4)))
|
||||
|
||||
(defn writer [c]
|
||||
(for i 0 3
|
||||
(def item (string i ":" (mod (hash c) 999)))
|
||||
(ev/sleep 0.1)
|
||||
(print "writer giving item " item " to " c "...")
|
||||
(ev/give c item))
|
||||
(print "Done!"))
|
||||
|
||||
(defn reader [name]
|
||||
(forever
|
||||
(def [_ c x] (ev/rselect ;channels))
|
||||
(print "reader " name " got " x " from " c)))
|
||||
|
||||
# Readers
|
||||
(each letter [:a :b :c :d :e :f :g]
|
||||
(ev/call reader letter))
|
||||
|
||||
# Writers
|
||||
(each c channels
|
||||
(ev/call writer c))
|
||||
37
examples/select2.janet
Normal file
37
examples/select2.janet
Normal file
@@ -0,0 +1,37 @@
|
||||
###
|
||||
### examples/select2.janet
|
||||
###
|
||||
### Mix reads and writes in select.
|
||||
###
|
||||
|
||||
(def c1 (ev/chan 40))
|
||||
(def c2 (ev/chan 40))
|
||||
(def c3 (ev/chan 40))
|
||||
(def c4 (ev/chan 40))
|
||||
|
||||
(def c5 (ev/chan 4))
|
||||
|
||||
(defn worker
|
||||
[c n x]
|
||||
(forever
|
||||
(ev/sleep n)
|
||||
(ev/give c x)))
|
||||
|
||||
(defn writer-worker
|
||||
[c]
|
||||
(forever
|
||||
(ev/sleep 0.2)
|
||||
(print "writing " (ev/take c))))
|
||||
|
||||
(ev/call worker c1 1 :item1)
|
||||
(ev/sleep 0.2)
|
||||
(ev/call worker c2 1 :item2)
|
||||
(ev/sleep 0.1)
|
||||
(ev/call worker c3 1 :item3)
|
||||
(ev/sleep 0.2)
|
||||
(ev/call worker c4 1 :item4)
|
||||
(ev/sleep 0.1)
|
||||
(ev/call worker c4 1 :item5)
|
||||
(ev/call writer-worker c5)
|
||||
|
||||
(forever (pp (ev/rselect c1 c2 c3 c4 [c5 :thing])))
|
||||
6
examples/tcpclient.janet
Normal file
6
examples/tcpclient.janet
Normal file
@@ -0,0 +1,6 @@
|
||||
(with [conn (net/connect "127.0.0.1" "8000")]
|
||||
(printf "Connected to %q!" conn)
|
||||
(:write conn "Echo...")
|
||||
(print "Wrote to connection...")
|
||||
(def res (:read conn 1024))
|
||||
(pp res))
|
||||
20
examples/tcpserver.janet
Normal file
20
examples/tcpserver.janet
Normal file
@@ -0,0 +1,20 @@
|
||||
(defn handler
|
||||
"Simple handler for connections."
|
||||
[stream]
|
||||
(defer (:close stream)
|
||||
(def id (gensym))
|
||||
(def b @"")
|
||||
(print "Connection " id "!")
|
||||
(while (:read stream 1024 b)
|
||||
(repeat 10 (print "work for " id " ...") (ev/sleep 0.1))
|
||||
(:write stream b)
|
||||
(buffer/clear b))
|
||||
(printf "Done %v!" id)))
|
||||
|
||||
# Run server.
|
||||
(let [server (net/server "127.0.0.1" "8000")]
|
||||
(print "Starting echo server on 127.0.0.1:8000")
|
||||
(forever
|
||||
(if-let [conn (:accept server)]
|
||||
(ev/call handler conn)
|
||||
(print "no new connections"))))
|
||||
22
examples/threaded-channels.janet
Normal file
22
examples/threaded-channels.janet
Normal file
@@ -0,0 +1,22 @@
|
||||
(def chan (ev/thread-chan 10))
|
||||
|
||||
(ev/spawn
|
||||
(ev/sleep 0)
|
||||
(print "started fiber!")
|
||||
(ev/give chan (math/random))
|
||||
(ev/give chan (math/random))
|
||||
(ev/give chan (math/random))
|
||||
(ev/sleep 0.5)
|
||||
(for i 0 10
|
||||
(print "giving to channel...")
|
||||
(ev/give chan (math/random))
|
||||
(ev/sleep 1))
|
||||
(print "finished fiber!")
|
||||
(:close chan))
|
||||
|
||||
(ev/do-thread
|
||||
(print "started thread!")
|
||||
(ev/sleep 1)
|
||||
(while (def x (do (print "taking from channel...") (ev/take chan)))
|
||||
(print "got " x " from thread!"))
|
||||
(print "finished thread!"))
|
||||
5
examples/udpclient.janet
Normal file
5
examples/udpclient.janet
Normal file
@@ -0,0 +1,5 @@
|
||||
(def conn (net/connect "127.0.0.1" "8009" :datagram))
|
||||
(:write conn (string/format "%q" (os/cryptorand 16)))
|
||||
(def x (:read conn 1024))
|
||||
(pp x)
|
||||
|
||||
6
examples/udpserver.janet
Normal file
6
examples/udpserver.janet
Normal file
@@ -0,0 +1,6 @@
|
||||
(def server (net/listen "127.0.0.1" "8009" :datagram))
|
||||
(while true
|
||||
(def buf @"")
|
||||
(def who (:recv-from server 1024 buf))
|
||||
(printf "got %q from %v, echoing!" buf who)
|
||||
(:send-to server who buf))
|
||||
29
examples/urlloader.janet
Normal file
29
examples/urlloader.janet
Normal file
@@ -0,0 +1,29 @@
|
||||
# An example of using Janet's extensible module system to import files from
|
||||
# URL. To try this, run `janet -l ./examples/urlloader.janet` from the command
|
||||
# line, and then at the REPL type:
|
||||
#
|
||||
# (import https://raw.githubusercontent.com/janet-lang/janet/master/examples/colors.janet :as c)
|
||||
#
|
||||
# This will import a file using curl. You can then try:
|
||||
#
|
||||
# (print (c/color :green "Hello!"))
|
||||
#
|
||||
# This is a bit of a toy example (it just shells out to curl), but it is very
|
||||
# powerful and will work well in many cases.
|
||||
|
||||
(defn- load-url
|
||||
[url args]
|
||||
(def p (os/spawn ["curl" url "-s"] :p {:out :pipe}))
|
||||
(def res (dofile (p :out) :source url ;args))
|
||||
(:wait p)
|
||||
res)
|
||||
|
||||
(defn- check-http-url
|
||||
[path]
|
||||
(if (or (string/has-prefix? "http://" path)
|
||||
(string/has-prefix? "https://" path))
|
||||
path))
|
||||
|
||||
# Add the module loader and path tuple to right places
|
||||
(array/push module/paths [check-http-url :janet-http])
|
||||
(put module/loaders :janet-http load-url)
|
||||
@@ -1,55 +0,0 @@
|
||||
!define MULTIUSER_EXECUTIONLEVEL Highest
|
||||
!define MULTIUSER_MUI
|
||||
!define MULTIUSER_INSTALLMODE_COMMANDLINE
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR "janet"
|
||||
!include "MultiUser.nsh"
|
||||
!include "MUI2.nsh"
|
||||
|
||||
Name "Janet"
|
||||
OutFile "janet-install.exe"
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MULTIUSER_PAGE_INSTALLMODE
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
Section "Janet" BfWSection
|
||||
SetOutPath $INSTDIR
|
||||
File "janet.exe"
|
||||
WriteUninstaller "$INSTDIR\janet-uninstall.exe"
|
||||
|
||||
# Start Menu
|
||||
CreateShortCut "$SMPROGRAMS\Janet.lnk" "$INSTDIR\janet.exe" "" ""
|
||||
SectionEnd
|
||||
|
||||
Function .onInit
|
||||
!insertmacro MULTIUSER_INIT
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
FunctionEnd
|
||||
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${BfWSection} "The Janet programming language."
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||
|
||||
Section "Uninstall"
|
||||
Delete "$INSTDIR\janet.exe"
|
||||
Delete "$INSTDIR\janet-uninstall.exe"
|
||||
RMDir "$INSTDIR"
|
||||
SectionEnd
|
||||
|
||||
Function un.onInit
|
||||
!insertmacro MULTIUSER_UNINIT
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
FunctionEnd
|
||||
235
janet.1
235
janet.1
@@ -3,25 +3,143 @@
|
||||
janet \- run the Janet language abstract machine
|
||||
.SH SYNOPSIS
|
||||
.B janet
|
||||
[\fB\-hvsrp\fR]
|
||||
[\fB\-e\fR \fIJANET SOURCE\fR]
|
||||
[\fB\-hvsrpnqik\fR]
|
||||
[\fB\-e\fR \fISOURCE\fR]
|
||||
[\fB\-E\fR \fISOURCE ...ARGUMENTS\fR]
|
||||
[\fB\-l\fR \fIMODULE\fR]
|
||||
[\fB\-m\fR \fIPATH\fR]
|
||||
[\fB\-c\fR \fIMODULE JIMAGE\fR]
|
||||
[\fB\-w\fR \fILEVEL\fR]
|
||||
[\fB\-x\fR \fILEVEL\fR]
|
||||
[\fB\-\-\fR]
|
||||
.IR script
|
||||
.IR args ...
|
||||
.BR script
|
||||
.BR args ...
|
||||
.SH DESCRIPTION
|
||||
Janet is a functional and imperative programming language and bytecode interpreter.
|
||||
It is a modern lisp, but lists are replaced by other data structures with better utility
|
||||
and performance (arrays, tables, structs, tuples). The language also bridging bridging
|
||||
It is a Lisp-like language, but lists are replaced by other data structures
|
||||
(arrays, tables, structs, tuples). The language also features bridging
|
||||
to native code written in C, meta-programming with macros, and bytecode assembly.
|
||||
|
||||
There is a repl for trying out the language, as well as the ability to run script files.
|
||||
This client program is separate from the core runtime, so Janet could be embedded
|
||||
into other programs. Try Janet in your browser at https://Janet-lang.org.
|
||||
into other programs. Try Janet in your browser at https://janet-lang.org.
|
||||
|
||||
Implemented in mostly standard C99, Janet runs on Windows, Linux and macOS.
|
||||
The few features that are not standard C99 (dynamic library loading, compiler
|
||||
specific optimizations), are fairly straight forward. Janet can be easily ported to
|
||||
most new platforms.
|
||||
|
||||
.SH REPL KEY-BINDINGS
|
||||
|
||||
.TP 16
|
||||
.BR Home
|
||||
Move cursor to the beginning of input line.
|
||||
|
||||
.TP 16
|
||||
.BR End
|
||||
Move cursor to the end of input line.
|
||||
|
||||
.TP 16
|
||||
.BR Left/Right
|
||||
Move cursor in input line.
|
||||
|
||||
.TP 16
|
||||
.BR Up/Down
|
||||
Go backwards and forwards through history.
|
||||
|
||||
.TP 16
|
||||
.BR Tab
|
||||
Complete current symbol, or show available completions.
|
||||
|
||||
.TP 16
|
||||
.BR Delete
|
||||
Delete one character after the cursor.
|
||||
|
||||
.TP 16
|
||||
.BR Backspace
|
||||
Delete one character before the cursor.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-A
|
||||
Move cursor to the beginning of input line.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-B
|
||||
Move cursor one character to the left.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-D
|
||||
If on a newline, indicate end of stream and exit the repl.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-E
|
||||
Move cursor to the end of input line.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-F
|
||||
Move cursor one character to the right.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-H
|
||||
Delete one character before the cursor.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-K
|
||||
Delete everything after the cursor on the input line.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-L
|
||||
Clear the screen.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-N/Ctrl\-P
|
||||
Go forwards and backwards through history.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-U
|
||||
Delete everything before the cursor on the input line.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-W
|
||||
Delete one word before the cursor.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-G
|
||||
Show documentation for the current symbol under the cursor.
|
||||
|
||||
.TP 16
|
||||
.BR Ctrl\-Q
|
||||
Clear the current command, including already typed lines.
|
||||
|
||||
.TP 16
|
||||
.BR Alt\-B/Alt\-F
|
||||
Move cursor backwards and forwards one word.
|
||||
|
||||
.TP 16
|
||||
.BR Alt\-D
|
||||
Delete one word after the cursor.
|
||||
|
||||
.TP 16
|
||||
.BR Alt\-,
|
||||
Go to earliest item in history.
|
||||
|
||||
.TP 16
|
||||
.BR Alt\-.
|
||||
Go to last item in history.
|
||||
|
||||
.LP
|
||||
|
||||
The repl keybindings are loosely based on a subset of GNU readline, although
|
||||
Janet does not use GNU readline internally for the repl. It is a limited
|
||||
substitute for GNU readline, and does not handle
|
||||
utf-8 input or other mutlibyte input well.
|
||||
|
||||
To disable the built-in repl input handling, pass the \fB\-s\fR option to Janet, and
|
||||
use a program like rlwrap with Janet to provide input.
|
||||
|
||||
For key bindings that operate on words, a word is considered to be a sequence
|
||||
of characters that does not contain whitespace.
|
||||
|
||||
.SH DOCUMENTATION
|
||||
|
||||
For more complete API documentation, run a REPL (Read Eval Print Loop), and use the doc macro to
|
||||
@@ -41,14 +159,43 @@ Shows the version text and exits immediately.
|
||||
Read raw input from stdin and forgo prompt history and other readline-like features.
|
||||
|
||||
.TP
|
||||
.BR \-q
|
||||
Quiet output. Don't print a repl prompt or expression results to stdout.
|
||||
.BR \-e\ code
|
||||
Execute a string of Janet source. Source code is executed in the order it is encountered, so earlier
|
||||
arguments are executed before later ones.
|
||||
|
||||
.TP
|
||||
.BR \-E\ code\ arguments...
|
||||
Execute a single Janet expression as a Janet short-fn, passing the remaining command line arguments to the expression. This allows
|
||||
more concise one-liners with command line arguments.
|
||||
|
||||
Example: janet -E '(print $0)' 12 is equivalent to '((short-fn (print $0)) 12)', which is in turn equivalent to
|
||||
`((fn [k] (print k)) 12)`
|
||||
|
||||
See docs for the `short-fn` function for more details.
|
||||
|
||||
.TP
|
||||
.BR \-d
|
||||
Enable debug mode. On all terminating signals as well the debug signal, this will
|
||||
cause the debugger to come up in the REPL. Same as calling (setdyn :debug true) in a
|
||||
default repl.
|
||||
|
||||
.TP
|
||||
.BR \-n
|
||||
Disable ANSI colors in the repl. Has no effect if no repl is run.
|
||||
|
||||
.TP
|
||||
.BR \-N
|
||||
Enable ANSI colors in the repl. Has no effect if no repl is run.
|
||||
|
||||
.TP
|
||||
.BR \-r
|
||||
Open a REPL (Read Eval Print Loop) after executing all sources. By default, if Janet is called with no
|
||||
arguments, a REPL is opened.
|
||||
|
||||
.TP
|
||||
.BR \-R
|
||||
If using the REPL, disable loading the user profile from the JANET_PROFILE environment variable.
|
||||
|
||||
.TP
|
||||
.BR \-p
|
||||
Turn on the persistent flag. By default, when Janet is executing commands from a file and encounters an error,
|
||||
@@ -56,19 +203,51 @@ it will immediately exit after printing the error message. In persistent mode, J
|
||||
after an error. Persistent mode can be good for debugging and testing.
|
||||
|
||||
.TP
|
||||
.BR \-e
|
||||
Execute a string of Janet source. Source code is executed in the order it is encountered, so earlier
|
||||
arguments are executed before later ones.
|
||||
.BR \-q
|
||||
Hide the logo in the repl.
|
||||
|
||||
.TP
|
||||
.BR \-l
|
||||
Load a Janet file before running a script or repl. Multiple files can be loaded
|
||||
.BR \-k
|
||||
Don't execute a script, only compile it to check for errors. Useful for linting scripts.
|
||||
|
||||
.TP
|
||||
.BR \-m\ syspath
|
||||
Set the dynamic binding :syspath to the string syspath so that Janet will load system modules
|
||||
from a directory different than the default. The default is set when Janet is built, and defaults to
|
||||
/usr/local/lib/janet on Linux/Posix, and C:/Janet/Library on Windows. This option supersedes JANET_PATH.
|
||||
|
||||
.TP
|
||||
.BR \-c\ source\ output
|
||||
Precompiles Janet source code into an image, a binary dump that can be efficiently loaded later.
|
||||
Source should be a path to the Janet module to compile, and output should be the file path of
|
||||
resulting image. Output should usually end with the .jimage extension.
|
||||
|
||||
.TP
|
||||
.BR \-i
|
||||
When this flag is passed, a script passed to the interpreter will be treated as a janet image file
|
||||
rather than a janet source file.
|
||||
|
||||
.TP
|
||||
.BR \-l\ lib
|
||||
Import a Janet module before running a script or repl. Multiple files can be loaded
|
||||
in this manner, and exports from each file will be made available to the script
|
||||
or repl.
|
||||
|
||||
.TP
|
||||
.BR \-w\ level
|
||||
Set the warning linting level for Janet.
|
||||
This linting level should be one of :relaxed, :none, :strict, :normal, or a
|
||||
Janet number. Any linting message that is of a greater lint level than this setting will be displayed as
|
||||
a warning, but not stop compilation or execution.
|
||||
.TP
|
||||
.BR \-x\ level
|
||||
Set the error linting level for Janet.
|
||||
This linting level should be one of :relaxed, :none, :strict, :normal, or a
|
||||
Janet number. Any linting message that is of a greater lint level will cause a compilation error
|
||||
and stop compilation.
|
||||
.TP
|
||||
.BR \-\-
|
||||
Stop parsing command line arguments. All arguments after this one will be considered file names.
|
||||
Stop parsing command line arguments. All arguments after this one will be considered file names
|
||||
and then arguments to the script.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
|
||||
@@ -76,9 +255,27 @@ Stop parsing command line arguments. All arguments after this one will be consid
|
||||
.RS
|
||||
The location to look for Janet libraries. This is the only environment variable Janet needs to
|
||||
find native and source code modules. If no JANET_PATH is set, Janet will look in
|
||||
/usr/local/lib/Janet for modules.
|
||||
To make Janet search multiple locations, modify the module.paths
|
||||
array in Janet.
|
||||
the default location set at compile time.
|
||||
.RE
|
||||
|
||||
.B JANET_PROFILE
|
||||
.RS
|
||||
Path to a profile file that the interpreter will load before entering the REPL. This profile file will
|
||||
not run for scripts, though. This behavior can be disabled with the -R option.
|
||||
.RE
|
||||
|
||||
.B JANET_HASHSEED
|
||||
.RS
|
||||
To disable randomization of Janet's PRF on start up, one can set this variable. This can have the
|
||||
effect of making programs deterministic that otherwise would depend on the random seed chosen at program start.
|
||||
This variable does nothing in the default configuration of Janet, as PRF is disabled by default. Also, JANET_REDUCED_OS
|
||||
cannot be defined for this variable to have an effect.
|
||||
.RE
|
||||
|
||||
.B NO_COLOR
|
||||
.RS
|
||||
Turn off color by default in the repl and in the error handler of scripts. This can be changed at runtime
|
||||
via dynamic bindings *err-color* and *pretty-format*, or via the command line parameters -n and -N.
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
|
||||
1
janet_win.rc
Normal file
1
janet_win.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_MYICON ICON "assets\icon.ico"
|
||||
291
meson.build
Normal file
291
meson.build
Normal file
@@ -0,0 +1,291 @@
|
||||
# Copyright (c) 2023 Calvin Rose and contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
project('janet', 'c',
|
||||
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||
version : '1.29.1')
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
header_path = join_paths(get_option('prefix'), get_option('includedir'), 'janet')
|
||||
|
||||
# Link math library on all systems
|
||||
cc = meson.get_compiler('c')
|
||||
m_dep = cc.find_library('m', required : false)
|
||||
dl_dep = cc.find_library('dl', required : false)
|
||||
android_spawn_dep = cc.find_library('android-spawn', required : false)
|
||||
thread_dep = dependency('threads')
|
||||
|
||||
# Link options
|
||||
if get_option('default_library') != 'static' and build_machine.system() != 'windows'
|
||||
add_project_link_arguments('-rdynamic', language : 'c')
|
||||
endif
|
||||
|
||||
# Generate custom janetconf.h
|
||||
conf = configuration_data()
|
||||
version_parts = meson.project_version().split('.')
|
||||
last_parts = version_parts[2].split('-')
|
||||
if last_parts.length() > 1
|
||||
conf.set_quoted('JANET_VERSION_EXTRA', '-' + last_parts[1])
|
||||
else
|
||||
conf.set_quoted('JANET_VERSION_EXTRA', '')
|
||||
endif
|
||||
conf.set('JANET_VERSION_MAJOR', version_parts[0].to_int())
|
||||
conf.set('JANET_VERSION_MINOR', version_parts[1].to_int())
|
||||
conf.set('JANET_VERSION_PATCH', last_parts[0].to_int())
|
||||
conf.set_quoted('JANET_VERSION', meson.project_version())
|
||||
# Use options
|
||||
conf.set_quoted('JANET_BUILD', get_option('git_hash'))
|
||||
conf.set('JANET_NO_NANBOX', not get_option('nanbox'))
|
||||
conf.set('JANET_SINGLE_THREADED', get_option('single_threaded'))
|
||||
conf.set('JANET_NO_DYNAMIC_MODULES', not get_option('dynamic_modules'))
|
||||
conf.set('JANET_NO_DOCSTRINGS', not get_option('docstrings'))
|
||||
conf.set('JANET_NO_SOURCEMAPS', not get_option('sourcemaps'))
|
||||
conf.set('JANET_NO_ASSEMBLER', not get_option('assembler'))
|
||||
conf.set('JANET_NO_PEG', not get_option('peg'))
|
||||
conf.set('JANET_NO_NET', not get_option('net'))
|
||||
conf.set('JANET_NO_EV', not get_option('ev') or get_option('single_threaded'))
|
||||
conf.set('JANET_REDUCED_OS', get_option('reduced_os'))
|
||||
conf.set('JANET_NO_INT_TYPES', not get_option('int_types'))
|
||||
conf.set('JANET_PRF', get_option('prf'))
|
||||
conf.set('JANET_RECURSION_GUARD', get_option('recursion_guard'))
|
||||
conf.set('JANET_MAX_PROTO_DEPTH', get_option('max_proto_depth'))
|
||||
conf.set('JANET_MAX_MACRO_EXPAND', get_option('max_macro_expand'))
|
||||
conf.set('JANET_STACK_MAX', get_option('stack_max'))
|
||||
conf.set('JANET_NO_UMASK', not get_option('umask'))
|
||||
conf.set('JANET_NO_REALPATH', not get_option('realpath'))
|
||||
conf.set('JANET_NO_PROCESSES', not get_option('processes'))
|
||||
conf.set('JANET_SIMPLE_GETLINE', get_option('simple_getline'))
|
||||
conf.set('JANET_EV_NO_EPOLL', not get_option('epoll'))
|
||||
conf.set('JANET_EV_NO_KQUEUE', not get_option('kqueue'))
|
||||
conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt'))
|
||||
conf.set('JANET_NO_FFI', not get_option('ffi'))
|
||||
conf.set('JANET_NO_FFI_JIT', not get_option('ffi_jit'))
|
||||
if get_option('os_name') != ''
|
||||
conf.set('JANET_OS_NAME', get_option('os_name'))
|
||||
endif
|
||||
if get_option('arch_name') != ''
|
||||
conf.set('JANET_ARCH_NAME', get_option('arch_name'))
|
||||
endif
|
||||
jconf = configure_file(output : 'janetconf.h',
|
||||
configuration : conf)
|
||||
|
||||
# Include directories
|
||||
incdir = include_directories(['src/include', '.'])
|
||||
|
||||
# Order is important here, as some headers
|
||||
# depend on other headers for the amalg target
|
||||
core_headers = [
|
||||
'src/core/features.h',
|
||||
'src/core/util.h',
|
||||
'src/core/state.h',
|
||||
'src/core/gc.h',
|
||||
'src/core/vector.h',
|
||||
'src/core/fiber.h',
|
||||
'src/core/regalloc.h',
|
||||
'src/core/compile.h',
|
||||
'src/core/emit.h',
|
||||
'src/core/symcache.h'
|
||||
]
|
||||
|
||||
core_src = [
|
||||
'src/core/abstract.c',
|
||||
'src/core/array.c',
|
||||
'src/core/asm.c',
|
||||
'src/core/buffer.c',
|
||||
'src/core/bytecode.c',
|
||||
'src/core/capi.c',
|
||||
'src/core/cfuns.c',
|
||||
'src/core/compile.c',
|
||||
'src/core/corelib.c',
|
||||
'src/core/debug.c',
|
||||
'src/core/emit.c',
|
||||
'src/core/ev.c',
|
||||
'src/core/ffi.c',
|
||||
'src/core/fiber.c',
|
||||
'src/core/gc.c',
|
||||
'src/core/inttypes.c',
|
||||
'src/core/io.c',
|
||||
'src/core/marsh.c',
|
||||
'src/core/math.c',
|
||||
'src/core/net.c',
|
||||
'src/core/os.c',
|
||||
'src/core/parse.c',
|
||||
'src/core/peg.c',
|
||||
'src/core/pp.c',
|
||||
'src/core/regalloc.c',
|
||||
'src/core/run.c',
|
||||
'src/core/specials.c',
|
||||
'src/core/state.c',
|
||||
'src/core/string.c',
|
||||
'src/core/strtod.c',
|
||||
'src/core/struct.c',
|
||||
'src/core/symcache.c',
|
||||
'src/core/table.c',
|
||||
'src/core/tuple.c',
|
||||
'src/core/util.c',
|
||||
'src/core/value.c',
|
||||
'src/core/vector.c',
|
||||
'src/core/vm.c',
|
||||
'src/core/wrap.c'
|
||||
]
|
||||
|
||||
boot_src = [
|
||||
'src/boot/array_test.c',
|
||||
'src/boot/boot.c',
|
||||
'src/boot/buffer_test.c',
|
||||
'src/boot/number_test.c',
|
||||
'src/boot/system_test.c',
|
||||
'src/boot/table_test.c',
|
||||
]
|
||||
|
||||
mainclient_src = [
|
||||
'src/mainclient/shell.c'
|
||||
]
|
||||
|
||||
# Build boot binary
|
||||
janet_boot = executable('janet-boot', core_src, boot_src,
|
||||
include_directories : incdir,
|
||||
c_args : '-DJANET_BOOTSTRAP',
|
||||
dependencies : [m_dep, dl_dep, thread_dep, android_spawn_dep],
|
||||
native : true)
|
||||
|
||||
# Build janet.c
|
||||
janetc = custom_target('janetc',
|
||||
input : [janet_boot],
|
||||
output : 'janet.c',
|
||||
capture : true,
|
||||
command : [
|
||||
janet_boot, meson.current_source_dir(),
|
||||
'JANET_PATH', janet_path
|
||||
])
|
||||
|
||||
janet_dependencies = [m_dep, dl_dep, android_spawn_dep]
|
||||
if not get_option('single_threaded')
|
||||
janet_dependencies += thread_dep
|
||||
endif
|
||||
|
||||
libjanet = library('janet', janetc,
|
||||
include_directories : incdir,
|
||||
dependencies : janet_dependencies,
|
||||
version: meson.project_version(),
|
||||
soversion: version_parts[0] + '.' + version_parts[1],
|
||||
install : true)
|
||||
|
||||
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
|
||||
# shaves off about 10k on linux x64, likely similar on other platforms.
|
||||
if cc.has_argument('-fvisibility=hidden')
|
||||
extra_cflags = ['-fvisibility=hidden']
|
||||
else
|
||||
extra_cflags = []
|
||||
endif
|
||||
janet_mainclient = executable('janet', janetc, mainclient_src,
|
||||
include_directories : incdir,
|
||||
dependencies : janet_dependencies,
|
||||
c_args : extra_cflags,
|
||||
install : true)
|
||||
|
||||
if meson.is_cross_build()
|
||||
native_cc = meson.get_compiler('c', native: true)
|
||||
if native_cc.has_argument('-fvisibility=hidden')
|
||||
extra_native_cflags = ['-fvisibility=hidden']
|
||||
else
|
||||
extra_native_cflags = []
|
||||
endif
|
||||
janet_nativeclient = executable('janet-native', janetc, mainclient_src,
|
||||
include_directories : incdir,
|
||||
dependencies : janet_dependencies,
|
||||
c_args : extra_native_cflags,
|
||||
native : true)
|
||||
else
|
||||
janet_nativeclient = janet_mainclient
|
||||
endif
|
||||
|
||||
# Documentation
|
||||
docs = custom_target('docs',
|
||||
input : ['tools/gendoc.janet'],
|
||||
output : ['doc.html'],
|
||||
capture : true,
|
||||
command : [janet_nativeclient, '@INPUT@'])
|
||||
|
||||
# Tests
|
||||
test_files = [
|
||||
'test/suite-array.janet',
|
||||
'test/suite-asm.janet',
|
||||
'test/suite-boot.janet',
|
||||
'test/suite-buffer.janet',
|
||||
'test/suite-capi.janet',
|
||||
'test/suite-cfuns.janet',
|
||||
'test/suite-compile.janet',
|
||||
'test/suite-corelib.janet',
|
||||
'test/suite-debug.janet',
|
||||
'test/suite-ev.janet',
|
||||
'test/suite-ffi.janet',
|
||||
'test/suite-inttypes.janet',
|
||||
'test/suite-io.janet',
|
||||
'test/suite-marsh.janet',
|
||||
'test/suite-math.janet',
|
||||
'test/suite-os.janet',
|
||||
'test/suite-parse.janet',
|
||||
'test/suite-peg.janet',
|
||||
'test/suite-pp.janet',
|
||||
'test/suite-specials.janet',
|
||||
'test/suite-string.janet',
|
||||
'test/suite-strtod.janet',
|
||||
'test/suite-struct.janet',
|
||||
'test/suite-symcache.janet',
|
||||
'test/suite-table.janet',
|
||||
'test/suite-unknown.janet',
|
||||
'test/suite-value.janet',
|
||||
'test/suite-vm.janet'
|
||||
]
|
||||
foreach t : test_files
|
||||
test(t, janet_nativeclient, args : files([t]), workdir : meson.current_source_dir())
|
||||
endforeach
|
||||
|
||||
# Repl
|
||||
run_target('repl', command : [janet_nativeclient])
|
||||
|
||||
# For use as meson subproject (wrap)
|
||||
janet_dep = declare_dependency(include_directories : incdir,
|
||||
link_with : libjanet)
|
||||
|
||||
# pkgconfig
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(libjanet,
|
||||
subdirs: 'janet',
|
||||
description: 'Library for the Janet programming language.')
|
||||
|
||||
# Installation
|
||||
install_man('janet.1')
|
||||
install_data(sources : ['tools/.keep'], install_dir : join_paths(get_option('libdir'), 'janet'))
|
||||
patched_janet = custom_target('patched-janeth',
|
||||
input : ['tools/patch-header.janet', 'src/include/janet.h', jconf],
|
||||
install : true,
|
||||
install_dir : join_paths(get_option('includedir'), 'janet'),
|
||||
build_by_default : true,
|
||||
output : ['janet.h'],
|
||||
command : [janet_nativeclient, '@INPUT@', '@OUTPUT@'])
|
||||
|
||||
# Create a version of the janet.h header that matches what jpm often expects
|
||||
if meson.version().version_compare('>=0.61')
|
||||
install_symlink('janet.h', pointing_to: 'janet/janet.h', install_dir: get_option('includedir'))
|
||||
endif
|
||||
|
||||
31
meson_options.txt
Normal file
31
meson_options.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
option('git_hash', type : 'string', value : 'meson')
|
||||
|
||||
option('single_threaded', type : 'boolean', value : false)
|
||||
option('nanbox', type : 'boolean', value : true)
|
||||
option('dynamic_modules', type : 'boolean', value : true)
|
||||
option('docstrings', type : 'boolean', value : true)
|
||||
option('sourcemaps', type : 'boolean', value : true)
|
||||
option('reduced_os', type : 'boolean', value : false)
|
||||
option('assembler', type : 'boolean', value : true)
|
||||
option('peg', type : 'boolean', value : true)
|
||||
option('int_types', type : 'boolean', value : true)
|
||||
option('prf', type : 'boolean', value : false)
|
||||
option('net', type : 'boolean', value : true)
|
||||
option('ev', type : 'boolean', value : true)
|
||||
option('processes', type : 'boolean', value : true)
|
||||
option('umask', type : 'boolean', value : true)
|
||||
option('realpath', type : 'boolean', value : true)
|
||||
option('simple_getline', type : 'boolean', value : false)
|
||||
option('epoll', type : 'boolean', value : false)
|
||||
option('kqueue', type : 'boolean', value : false)
|
||||
option('interpreter_interrupt', type : 'boolean', value : false)
|
||||
option('ffi', type : 'boolean', value : true)
|
||||
option('ffi_jit', type : 'boolean', value : true)
|
||||
|
||||
option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024)
|
||||
option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200)
|
||||
option('max_macro_expand', type : 'integer', min : 1, max : 8000, value : 200)
|
||||
option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7fffffff)
|
||||
|
||||
option('arch_name', type : 'string', value: '')
|
||||
option('os_name', type : 'string', value: '')
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,16 +20,16 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
#include "tests.h"
|
||||
|
||||
int array_test() {
|
||||
|
||||
int i;
|
||||
JanetArray *array1, *array2;
|
||||
|
||||
janet_init();
|
||||
|
||||
array1 = janet_array(10);
|
||||
array2 = janet_array(0);
|
||||
|
||||
@@ -62,7 +62,5 @@ int main() {
|
||||
|
||||
assert(array1->count == 5);
|
||||
|
||||
janet_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,21 +20,92 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include "tests.h"
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
#include <direct.h>
|
||||
#define chdir(x) _chdir(x)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern const unsigned char *janet_gen_boot;
|
||||
extern int32_t janet_gen_boot_size;
|
||||
|
||||
int main() {
|
||||
int main(int argc, const char **argv) {
|
||||
|
||||
/* Init janet */
|
||||
janet_init();
|
||||
|
||||
/* Run tests */
|
||||
array_test();
|
||||
buffer_test();
|
||||
number_test();
|
||||
system_test();
|
||||
table_test();
|
||||
|
||||
/* C tests passed */
|
||||
|
||||
/* Set up VM */
|
||||
int status;
|
||||
JanetTable *env;
|
||||
|
||||
/* Set up VM */
|
||||
janet_init();
|
||||
env = janet_core_env();
|
||||
env = janet_core_env(NULL);
|
||||
|
||||
/* Create args tuple */
|
||||
JanetArray *args = janet_array(argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
janet_array_push(args, janet_cstringv(argv[i]));
|
||||
janet_def(env, "boot/args", janet_wrap_array(args), "Command line arguments.");
|
||||
|
||||
/* Add in options from janetconf.h so boot.janet can configure the image as needed. */
|
||||
JanetTable *opts = janet_table(0);
|
||||
#ifdef JANET_NO_DOCSTRINGS
|
||||
janet_table_put(opts, janet_ckeywordv("no-docstrings"), janet_wrap_true());
|
||||
#endif
|
||||
#ifdef JANET_NO_SOURCEMAPS
|
||||
janet_table_put(opts, janet_ckeywordv("no-sourcemaps"), janet_wrap_true());
|
||||
#endif
|
||||
janet_def(env, "boot/config", janet_wrap_table(opts), "Boot options");
|
||||
|
||||
/* Run bootstrap script to generate core image */
|
||||
status = janet_dobytes(env, janet_gen_boot, janet_gen_boot_size, "boot.janet", NULL);
|
||||
const char *boot_filename;
|
||||
#ifdef JANET_NO_SOURCEMAPS
|
||||
boot_filename = NULL;
|
||||
#else
|
||||
boot_filename = "boot.janet";
|
||||
#endif
|
||||
|
||||
int chdir_status = chdir(argv[1]);
|
||||
if (chdir_status) {
|
||||
fprintf(stderr, "Could not change to directory %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE *boot_file = fopen("src/boot/boot.janet", "rb");
|
||||
if (NULL == boot_file) {
|
||||
fprintf(stderr, "Could not open src/boot/boot.janet\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Slurp file into buffer */
|
||||
fseek(boot_file, 0, SEEK_END);
|
||||
size_t boot_size = ftell(boot_file);
|
||||
fseek(boot_file, 0, SEEK_SET);
|
||||
unsigned char *boot_buffer = janet_malloc(boot_size);
|
||||
if (NULL == boot_buffer) {
|
||||
fprintf(stderr, "Failed to allocate boot buffer\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!fread(boot_buffer, 1, boot_size, boot_file)) {
|
||||
fprintf(stderr, "Failed to read into boot buffer\n");
|
||||
exit(1);
|
||||
}
|
||||
fclose(boot_file);
|
||||
|
||||
status = janet_dobytes(env, boot_buffer, (int32_t) boot_size, boot_filename, NULL);
|
||||
janet_free(boot_buffer);
|
||||
|
||||
/* Deinitialize vm */
|
||||
janet_deinit();
|
||||
|
||||
4261
src/boot/boot.janet
4261
src/boot/boot.janet
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,16 +20,16 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
#include "tests.h"
|
||||
|
||||
int buffer_test() {
|
||||
|
||||
int i;
|
||||
JanetBuffer *buffer1, *buffer2;
|
||||
|
||||
janet_init();
|
||||
|
||||
buffer1 = janet_buffer(100);
|
||||
buffer2 = janet_buffer(0);
|
||||
|
||||
@@ -58,7 +58,5 @@ int main() {
|
||||
assert(buffer1->data[i] == buffer2->data[i]);
|
||||
}
|
||||
|
||||
janet_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,11 +20,13 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
/* Check a subset of numbers against system implementation.
|
||||
* Note that this depends on the system implementation being correct,
|
||||
* which may not be the case for old or non compliant systems. Also,
|
||||
@@ -36,14 +38,12 @@ static void test_valid_str(const char *str) {
|
||||
double cnum, jnum;
|
||||
jnum = 0.0;
|
||||
cnum = atof(str);
|
||||
err = janet_scan_number((const uint8_t *) str, strlen(str), &jnum);
|
||||
err = janet_scan_number((const uint8_t *) str, (int32_t) strlen(str), &jnum);
|
||||
assert(!err);
|
||||
assert(cnum == jnum);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
janet_init();
|
||||
int number_test() {
|
||||
|
||||
test_valid_str("1.0");
|
||||
test_valid_str("1");
|
||||
@@ -63,7 +63,5 @@ int main() {
|
||||
test_valid_str("0000000011111111111111111111111111");
|
||||
test_valid_str(".112312333333323123123123123123123");
|
||||
|
||||
janet_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,11 +20,14 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
int main() {
|
||||
#include "tests.h"
|
||||
|
||||
int system_test() {
|
||||
|
||||
#ifdef JANET_32
|
||||
assert(sizeof(void *) == 4);
|
||||
@@ -32,8 +35,6 @@ int main() {
|
||||
assert(sizeof(void *) == 8);
|
||||
#endif
|
||||
|
||||
janet_init();
|
||||
|
||||
/* Reflexive testing and nanbox testing */
|
||||
assert(janet_equals(janet_wrap_nil(), janet_wrap_nil()));
|
||||
assert(janet_equals(janet_wrap_false(), janet_wrap_false()));
|
||||
@@ -44,11 +45,30 @@ int main() {
|
||||
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
|
||||
assert(janet_equals(janet_wrap_number(1.4), janet_wrap_number(1.4)));
|
||||
assert(janet_equals(janet_wrap_number(3.14159265), janet_wrap_number(3.14159265)));
|
||||
#ifdef NAN
|
||||
assert(janet_checktype(janet_wrap_number(NAN), JANET_NUMBER));
|
||||
#else
|
||||
assert(janet_checktype(janet_wrap_number(0.0 / 0.0), JANET_NUMBER));
|
||||
#endif
|
||||
|
||||
assert(NULL != &janet_wrap_nil);
|
||||
|
||||
assert(janet_equals(janet_cstringv("a string."), janet_cstringv("a string.")));
|
||||
assert(janet_equals(janet_csymbolv("sym"), janet_csymbolv("sym")));
|
||||
|
||||
janet_deinit();
|
||||
Janet *t1 = janet_tuple_begin(3);
|
||||
t1[0] = janet_wrap_nil();
|
||||
t1[1] = janet_wrap_integer(4);
|
||||
t1[2] = janet_cstringv("hi");
|
||||
Janet tuple1 = janet_wrap_tuple(janet_tuple_end(t1));
|
||||
|
||||
Janet *t2 = janet_tuple_begin(3);
|
||||
t2[0] = janet_wrap_nil();
|
||||
t2[1] = janet_wrap_integer(4);
|
||||
t2[2] = janet_cstringv("hi");
|
||||
Janet tuple2 = janet_wrap_tuple(janet_tuple_end(t2));
|
||||
|
||||
assert(janet_equals(tuple1, tuple2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,15 +20,15 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
#include "tests.h"
|
||||
|
||||
int table_test() {
|
||||
|
||||
JanetTable *t1, *t2;
|
||||
|
||||
janet_init();
|
||||
|
||||
t1 = janet_table(10);
|
||||
t2 = janet_table(0);
|
||||
|
||||
@@ -61,7 +61,11 @@ int main() {
|
||||
assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key1")), janet_wrap_integer(10)));
|
||||
assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key2")), janet_wrap_integer(100)));
|
||||
|
||||
janet_deinit();
|
||||
assert(t2->count == 4);
|
||||
assert(janet_equals(janet_table_remove(t2, janet_csymbolv("t2key1")), janet_wrap_integer(10)));
|
||||
assert(t2->count == 3);
|
||||
assert(janet_equals(janet_table_remove(t2, janet_csymbolv("t2key2")), janet_wrap_integer(100)));
|
||||
assert(t2->count == 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
src/boot/tests.h
Normal file
11
src/boot/tests.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef TESTS_H_DNMBUYYL
|
||||
#define TESTS_H_DNMBUYYL
|
||||
|
||||
/* Tests */
|
||||
extern int array_test();
|
||||
extern int buffer_test();
|
||||
extern int number_test();
|
||||
extern int system_test();
|
||||
extern int table_test();
|
||||
|
||||
#endif /* end of include guard: TESTS_H_DNMBUYYL */
|
||||
66
src/conf/janetconf.h
Normal file
66
src/conf/janetconf.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* This will be generated by the build system if this file is not used */
|
||||
|
||||
#ifndef JANETCONF_H
|
||||
#define JANETCONF_H
|
||||
|
||||
#define JANET_VERSION_MAJOR 1
|
||||
#define JANET_VERSION_MINOR 29
|
||||
#define JANET_VERSION_PATCH 1
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.29.1"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
/* These settings all affect linking, so use cautiously. */
|
||||
/* #define JANET_SINGLE_THREADED */
|
||||
/* #define JANET_NO_DYNAMIC_MODULES */
|
||||
/* #define JANET_NO_NANBOX */
|
||||
/* #define JANET_API __attribute__((visibility ("default"))) */
|
||||
|
||||
/* These settings should be specified before amalgamation is
|
||||
* built. Any build with these set should be considered non-standard, and
|
||||
* certain Janet libraries should be expected not to work. */
|
||||
/* #define JANET_NO_DOCSTRINGS */
|
||||
/* #define JANET_NO_SOURCEMAPS */
|
||||
/* #define JANET_REDUCED_OS */
|
||||
/* #define JANET_NO_PROCESSES */
|
||||
/* #define JANET_NO_ASSEMBLER */
|
||||
/* #define JANET_NO_PEG */
|
||||
/* #define JANET_NO_NET */
|
||||
/* #define JANET_NO_INT_TYPES */
|
||||
/* #define JANET_NO_EV */
|
||||
/* #define JANET_NO_REALPATH */
|
||||
/* #define JANET_NO_SYMLINKS */
|
||||
/* #define JANET_NO_UMASK */
|
||||
/* #define JANET_NO_THREADS */
|
||||
/* #define JANET_NO_FFI */
|
||||
/* #define JANET_NO_FFI_JIT */
|
||||
|
||||
/* Other settings */
|
||||
/* #define JANET_DEBUG */
|
||||
/* #define JANET_PRF */
|
||||
/* #define JANET_NO_UTC_MKTIME */
|
||||
/* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */
|
||||
/* #define JANET_EXIT(msg) do { printf("C assert failed executing janet: %s\n", msg); exit(1); } while (0) */
|
||||
/* #define JANET_TOP_LEVEL_SIGNAL(msg) call_my_function((msg), stderr) */
|
||||
/* #define JANET_RECURSION_GUARD 1024 */
|
||||
/* #define JANET_MAX_PROTO_DEPTH 200 */
|
||||
/* #define JANET_MAX_MACRO_EXPAND 200 */
|
||||
/* #define JANET_STACK_MAX 16384 */
|
||||
/* #define JANET_OS_NAME my-custom-os */
|
||||
/* #define JANET_ARCH_NAME pdp-8 */
|
||||
/* #define JANET_EV_NO_EPOLL */
|
||||
/* #define JANET_EV_NO_KQUEUE */
|
||||
/* #define JANET_NO_INTERPRETER_INTERRUPT */
|
||||
|
||||
/* Custom vm allocator support */
|
||||
/* #include <mimalloc.h> */
|
||||
/* #define janet_malloc(X) mi_malloc((X)) */
|
||||
/* #define janet_realloc(X, Y) mi_realloc((X), (Y)) */
|
||||
/* #define janet_calloc(X, Y) mi_calloc((X), (Y)) */
|
||||
/* #define janet_free(X) mi_free((X)) */
|
||||
|
||||
/* Main client settings, does not affect library code */
|
||||
/* #define JANET_SIMPLE_GETLINE */
|
||||
|
||||
#endif /* end of include guard: JANETCONF_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,16 +21,202 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#include "gc.h"
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
#ifdef JANET_EV
|
||||
#ifdef JANET_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Create new userdata */
|
||||
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
|
||||
char *data = janet_gcalloc(JANET_MEMORY_ABSTRACT, sizeof(JanetAbstractHeader) + size);
|
||||
JanetAbstractHeader *header = (JanetAbstractHeader *)data;
|
||||
void *a = data + sizeof(JanetAbstractHeader);
|
||||
void *janet_abstract_begin(const JanetAbstractType *atype, size_t size) {
|
||||
JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_NONE,
|
||||
sizeof(JanetAbstractHead) + size);
|
||||
header->size = size;
|
||||
header->type = atype;
|
||||
return a;
|
||||
return (void *) & (header->data);
|
||||
}
|
||||
|
||||
void *janet_abstract_end(void *x) {
|
||||
janet_gc_settype((void *)(janet_abstract_head(x)), JANET_MEMORY_ABSTRACT);
|
||||
return x;
|
||||
}
|
||||
|
||||
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
|
||||
return janet_abstract_end(janet_abstract_begin(atype, size));
|
||||
}
|
||||
|
||||
#ifdef JANET_EV
|
||||
|
||||
/*
|
||||
* Threaded abstracts
|
||||
*/
|
||||
|
||||
void *janet_abstract_begin_threaded(const JanetAbstractType *atype, size_t size) {
|
||||
JanetAbstractHead *header = janet_malloc(sizeof(JanetAbstractHead) + size);
|
||||
if (NULL == header) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm.next_collection += size + sizeof(JanetAbstractHead);
|
||||
header->gc.flags = JANET_MEMORY_THREADED_ABSTRACT;
|
||||
header->gc.data.next = NULL; /* Clear memory for address sanitizers */
|
||||
header->gc.data.refcount = 1;
|
||||
header->size = size;
|
||||
header->type = atype;
|
||||
void *abstract = (void *) & (header->data);
|
||||
janet_table_put(&janet_vm.threaded_abstracts, janet_wrap_abstract(abstract), janet_wrap_false());
|
||||
return abstract;
|
||||
}
|
||||
|
||||
void *janet_abstract_end_threaded(void *x) {
|
||||
janet_gc_settype((void *)(janet_abstract_head(x)), JANET_MEMORY_THREADED_ABSTRACT);
|
||||
return x;
|
||||
}
|
||||
|
||||
void *janet_abstract_threaded(const JanetAbstractType *atype, size_t size) {
|
||||
return janet_abstract_end_threaded(janet_abstract_begin_threaded(atype, size));
|
||||
}
|
||||
|
||||
/* Refcounting primitives and sync primitives */
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
|
||||
size_t janet_os_mutex_size(void) {
|
||||
return sizeof(CRITICAL_SECTION);
|
||||
}
|
||||
|
||||
size_t janet_os_rwlock_size(void) {
|
||||
return sizeof(void *);
|
||||
}
|
||||
|
||||
static int32_t janet_incref(JanetAbstractHead *ab) {
|
||||
return InterlockedIncrement((LONG volatile *) &ab->gc.data.refcount);
|
||||
}
|
||||
|
||||
static int32_t janet_decref(JanetAbstractHead *ab) {
|
||||
return InterlockedDecrement((LONG volatile *) &ab->gc.data.refcount);
|
||||
}
|
||||
|
||||
void janet_os_mutex_init(JanetOSMutex *mutex) {
|
||||
InitializeCriticalSection((CRITICAL_SECTION *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_deinit(JanetOSMutex *mutex) {
|
||||
DeleteCriticalSection((CRITICAL_SECTION *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_lock(JanetOSMutex *mutex) {
|
||||
EnterCriticalSection((CRITICAL_SECTION *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_unlock(JanetOSMutex *mutex) {
|
||||
/* error handling? May want to keep counter */
|
||||
LeaveCriticalSection((CRITICAL_SECTION *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_init(JanetOSRWLock *rwlock) {
|
||||
InitializeSRWLock((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_deinit(JanetOSRWLock *rwlock) {
|
||||
/* no op? */
|
||||
(void) rwlock;
|
||||
}
|
||||
|
||||
void janet_os_rwlock_rlock(JanetOSRWLock *rwlock) {
|
||||
AcquireSRWLockShared((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wlock(JanetOSRWLock *rwlock) {
|
||||
AcquireSRWLockExclusive((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_runlock(JanetOSRWLock *rwlock) {
|
||||
ReleaseSRWLockShared((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
|
||||
ReleaseSRWLockExclusive((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
size_t janet_os_mutex_size(void) {
|
||||
return sizeof(pthread_mutex_t);
|
||||
}
|
||||
|
||||
size_t janet_os_rwlock_size(void) {
|
||||
return sizeof(pthread_rwlock_t);
|
||||
}
|
||||
|
||||
static int32_t janet_incref(JanetAbstractHead *ab) {
|
||||
return __atomic_add_fetch(&ab->gc.data.refcount, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static int32_t janet_decref(JanetAbstractHead *ab) {
|
||||
return __atomic_add_fetch(&ab->gc.data.refcount, -1, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
void janet_os_mutex_init(JanetOSMutex *mutex) {
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init((pthread_mutex_t *) mutex, &attr);
|
||||
}
|
||||
|
||||
void janet_os_mutex_deinit(JanetOSMutex *mutex) {
|
||||
pthread_mutex_destroy((pthread_mutex_t *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_lock(JanetOSMutex *mutex) {
|
||||
pthread_mutex_lock((pthread_mutex_t *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_unlock(JanetOSMutex *mutex) {
|
||||
int ret = pthread_mutex_unlock((pthread_mutex_t *) mutex);
|
||||
if (ret) janet_panic("cannot release lock");
|
||||
}
|
||||
|
||||
void janet_os_rwlock_init(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_init((pthread_rwlock_t *) rwlock, NULL);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_deinit(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_destroy((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_rlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_rdlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_wrlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_runlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int32_t janet_abstract_incref(void *abst) {
|
||||
return janet_incref(janet_abstract_head(abst));
|
||||
}
|
||||
|
||||
int32_t janet_abstract_decref(void *abst) {
|
||||
return janet_decref(janet_abstract_head(abst));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
283
src/core/array.c
283
src/core/array.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,18 +21,22 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Initializes an array */
|
||||
JanetArray *janet_array_init(JanetArray *array, int32_t capacity) {
|
||||
/* Creates a new array */
|
||||
JanetArray *janet_array(int32_t capacity) {
|
||||
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
|
||||
Janet *data = NULL;
|
||||
if (capacity > 0) {
|
||||
data = (Janet *) malloc(sizeof(Janet) * capacity);
|
||||
janet_vm.next_collection += capacity * sizeof(Janet);
|
||||
data = (Janet *) janet_malloc(sizeof(Janet) * (size_t) capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -43,26 +47,16 @@ JanetArray *janet_array_init(JanetArray *array, int32_t capacity) {
|
||||
return array;
|
||||
}
|
||||
|
||||
void janet_array_deinit(JanetArray *array) {
|
||||
free(array->data);
|
||||
}
|
||||
|
||||
/* Creates a new array */
|
||||
JanetArray *janet_array(int32_t capacity) {
|
||||
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
|
||||
return janet_array_init(array, capacity);
|
||||
}
|
||||
|
||||
/* Creates a new array from n elements. */
|
||||
JanetArray *janet_array_n(const Janet *elements, int32_t n) {
|
||||
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
|
||||
array->capacity = n;
|
||||
array->count = n;
|
||||
array->data = malloc(sizeof(Janet) * n);
|
||||
array->data = janet_malloc(sizeof(Janet) * (size_t) n);
|
||||
if (!array->data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(array->data, elements, sizeof(Janet) * n);
|
||||
safe_memcpy(array->data, elements, sizeof(Janet) * n);
|
||||
return array;
|
||||
}
|
||||
|
||||
@@ -71,11 +65,14 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth) {
|
||||
Janet *newData;
|
||||
Janet *old = array->data;
|
||||
if (capacity <= array->capacity) return;
|
||||
capacity *= growth;
|
||||
newData = realloc(old, capacity * sizeof(Janet));
|
||||
int64_t new_capacity = ((int64_t) capacity) * growth;
|
||||
if (new_capacity > INT32_MAX) new_capacity = INT32_MAX;
|
||||
capacity = (int32_t) new_capacity;
|
||||
newData = janet_realloc(old, capacity * sizeof(Janet));
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm.next_collection += (capacity - array->capacity) * sizeof(Janet);
|
||||
array->data = newData;
|
||||
array->capacity = capacity;
|
||||
}
|
||||
@@ -96,6 +93,9 @@ void janet_array_setcount(JanetArray *array, int32_t count) {
|
||||
|
||||
/* Push a value to the top of the array */
|
||||
void janet_array_push(JanetArray *array, Janet x) {
|
||||
if (array->count == INT32_MAX) {
|
||||
janet_panic("array overflow");
|
||||
}
|
||||
int32_t newcount = array->count + 1;
|
||||
janet_array_ensure(array, newcount, 2);
|
||||
array->data[array->count] = x;
|
||||
@@ -122,36 +122,81 @@ Janet janet_array_peek(JanetArray *array) {
|
||||
|
||||
/* C Functions */
|
||||
|
||||
static Janet cfun_array_new(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_new,
|
||||
"(array/new capacity)",
|
||||
"Creates a new empty array with a pre-allocated capacity. The same as "
|
||||
"`(array)` but can be more efficient if the maximum size of an array is known.") {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
JanetArray *array = janet_array(cap);
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_array_pop(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_new_filled,
|
||||
"(array/new-filled count &opt value)",
|
||||
"Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t count = janet_getnat(argv, 0);
|
||||
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
|
||||
JanetArray *array = janet_array(count);
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
array->data[i] = x;
|
||||
}
|
||||
array->count = count;
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_array_fill,
|
||||
"(array/fill arr &opt value)",
|
||||
"Replace all elements of an array with `value` (defaulting to nil) without changing the length of the array. "
|
||||
"Returns the modified array.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
|
||||
for (int32_t i = 0; i < array->count; i++) {
|
||||
array->data[i] = x;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_array_pop,
|
||||
"(array/pop arr)",
|
||||
"Remove the last element of the array and return it. If the array is empty, will return nil. Modifies "
|
||||
"the input array.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
return janet_array_pop(array);
|
||||
}
|
||||
|
||||
static Janet cfun_array_peek(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_peek,
|
||||
"(array/peek arr)",
|
||||
"Returns the last element of the array. Does not modify the array.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
return janet_array_peek(array);
|
||||
}
|
||||
|
||||
static Janet cfun_array_push(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_push,
|
||||
"(array/push arr x)",
|
||||
"Insert an element in the end of an array. Modifies the input array and returns it.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
if (INT32_MAX - argc + 1 <= array->count) {
|
||||
janet_panic("array overflow");
|
||||
}
|
||||
int32_t newcount = array->count - 1 + argc;
|
||||
janet_array_ensure(array, newcount, 2);
|
||||
if (argc > 1) memcpy(array->data + array->count, argv + 1, (argc - 1) * sizeof(Janet));
|
||||
if (argc > 1) memcpy(array->data + array->count, argv + 1, (size_t)(argc - 1) * sizeof(Janet));
|
||||
array->count = newcount;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_array_ensure(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_ensure,
|
||||
"(array/ensure arr capacity growth)",
|
||||
"Ensures that the memory backing the array is large enough for `capacity` "
|
||||
"items at the given rate of growth. `capacity` and `growth` must be integers. "
|
||||
"If the backing capacity is already enough, then this function does nothing. "
|
||||
"Otherwise, the backing memory will be reallocated so that there is enough space.") {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
int32_t newcount = janet_getinteger(argv, 1);
|
||||
@@ -161,16 +206,28 @@ static Janet cfun_array_ensure(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_array_slice(int32_t argc, Janet *argv) {
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JANET_CORE_FN(cfun_array_slice,
|
||||
"(array/slice arrtup &opt start end)",
|
||||
"Takes a slice of array or tuple from `start` to `end`. The range is half open, "
|
||||
"[start, end). Indexes can also be negative, indicating indexing from the "
|
||||
"end of the array. By default, `start` is 0 and `end` is the length of the array. "
|
||||
"Note that index -1 is synonymous with index `(length arrtup)` to allow a full "
|
||||
"negative slice range. Returns a new array.") {
|
||||
JanetView view = janet_getindexed(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JanetArray *array = janet_array(range.end - range.start);
|
||||
memcpy(array->data, view.items + range.start, sizeof(Janet) * (range.end - range.start));
|
||||
if (array->data)
|
||||
memcpy(array->data, view.items + range.start, sizeof(Janet) * (range.end - range.start));
|
||||
array->count = range.end - range.start;
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_array_concat(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_concat,
|
||||
"(array/concat arr & parts)",
|
||||
"Concatenates a variable number of arrays (and tuples) into the first argument, "
|
||||
"which must be an array. If any of the parts are arrays or tuples, their elements will "
|
||||
"be inserted into the array. Otherwise, each part in `parts` will be appended to `arr` in order. "
|
||||
"Return the modified array `arr`.") {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
@@ -180,21 +237,30 @@ static Janet cfun_array_concat(int32_t argc, Janet *argv) {
|
||||
janet_array_push(array, argv[i]);
|
||||
break;
|
||||
case JANET_ARRAY:
|
||||
case JANET_TUPLE:
|
||||
{
|
||||
int32_t j, len;
|
||||
const Janet *vals;
|
||||
case JANET_TUPLE: {
|
||||
int32_t j, len = 0;
|
||||
const Janet *vals = NULL;
|
||||
janet_indexed_view(argv[i], &vals, &len);
|
||||
if (array->data == vals) {
|
||||
int32_t newcount = array->count + len;
|
||||
janet_array_ensure(array, newcount, 2);
|
||||
janet_indexed_view(argv[i], &vals, &len);
|
||||
for (j = 0; j < len; j++)
|
||||
janet_array_push(array, vals[j]);
|
||||
}
|
||||
break;
|
||||
for (j = 0; j < len; j++)
|
||||
janet_array_push(array, vals[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_array_insert(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_array_insert,
|
||||
"(array/insert arr at & xs)",
|
||||
"Insert all `xs` into array `arr` at index `at`. `at` should be an integer between "
|
||||
"0 and the length of the array. A negative value for `at` will index backwards from "
|
||||
"the end of the array, such that inserting at -1 appends to the array. "
|
||||
"Returns the array.") {
|
||||
size_t chunksize, restsize;
|
||||
janet_arity(argc, 2, -1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
@@ -206,66 +272,99 @@ static Janet cfun_array_insert(int32_t argc, Janet *argv) {
|
||||
janet_panicf("insertion index %d out of range [0,%d]", at, array->count);
|
||||
chunksize = (argc - 2) * sizeof(Janet);
|
||||
restsize = (array->count - at) * sizeof(Janet);
|
||||
if (INT32_MAX - (argc - 2) < array->count) {
|
||||
janet_panic("array overflow");
|
||||
}
|
||||
janet_array_ensure(array, array->count + argc - 2, 2);
|
||||
memmove(array->data + at + argc - 2,
|
||||
array->data + at,
|
||||
restsize);
|
||||
memcpy(array->data + at, argv + 2, chunksize);
|
||||
if (restsize) {
|
||||
memmove(array->data + at + argc - 2,
|
||||
array->data + at,
|
||||
restsize);
|
||||
}
|
||||
safe_memcpy(array->data + at, argv + 2, chunksize);
|
||||
array->count += (argc - 2);
|
||||
return janet_wrap_array(array);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg array_cfuns[] = {
|
||||
{"array/new", cfun_array_new,
|
||||
JDOC("(array/new capacity)\n\n"
|
||||
"Creates a new empty array with a pre-allocated capacity. The same as "
|
||||
"(array) but can be more efficient if the maximum size of an array is known.")
|
||||
},
|
||||
{"array/pop", cfun_array_pop,
|
||||
JDOC("(array/pop arr)\n\n"
|
||||
"Remove the last element of the array and return it. If the array is empty, will return nil. Modifies "
|
||||
"the input array.")
|
||||
},
|
||||
{"array/peek", cfun_array_peek,
|
||||
JDOC("(array/peek arr)\n\n"
|
||||
"Returns the last element of the array. Does not modify the array.")
|
||||
},
|
||||
{"array/push", cfun_array_push,
|
||||
JDOC("(array/push arr x)\n\n"
|
||||
"Insert an element in the end of an array. Modifies the input array and returns it.")
|
||||
},
|
||||
{"array/ensure", cfun_array_ensure,
|
||||
JDOC("(array/ensure arr capacity)\n\n"
|
||||
"Ensures that the memory backing the array has enough memory for capacity "
|
||||
"items. Capacity must be an integer. If the backing capacity is already enough, "
|
||||
"then this function does nothing. Otherwise, the backing memory will be reallocated "
|
||||
"so that there is enough space.")
|
||||
},
|
||||
{"array/slice", cfun_array_slice,
|
||||
JDOC("(array/slice arrtup [, start=0 [, end=(length arrtup)]])\n\n"
|
||||
"Takes a slice of array or tuple from start to end. The range is half open, "
|
||||
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
|
||||
"end of the array. By default, start is 0 and end is the length of the array. "
|
||||
"Returns a new array.")
|
||||
},
|
||||
{"array/concat", cfun_array_concat,
|
||||
JDOC("(array/concat arr & parts)\n\n"
|
||||
"Concatenates a variadic number of arrays (and tuples) into the first argument "
|
||||
"which must an array. If any of the parts are arrays or tuples, their elements will "
|
||||
"be inserted into the array. Otherwise, each part in parts will be appended to arr in order. "
|
||||
"Return the modified array arr.")
|
||||
},
|
||||
{"array/insert", cfun_array_insert,
|
||||
JDOC("(array/insert arr at & xs)\n\n"
|
||||
"Insert all of xs into array arr at index at. at should be an integer "
|
||||
"0 and the length of the array. A negative value for at will index from "
|
||||
"the end of the array, such that inserting at -1 appends to the array. "
|
||||
"Returns the array.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
JANET_CORE_FN(cfun_array_remove,
|
||||
"(array/remove arr at &opt n)",
|
||||
"Remove up to `n` elements starting at index `at` in array `arr`. `at` can index from "
|
||||
"the end of the array with a negative index, and `n` must be a non-negative integer. "
|
||||
"By default, `n` is 1. "
|
||||
"Returns the array.") {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
int32_t at = janet_getinteger(argv, 1);
|
||||
int32_t n = 1;
|
||||
if (at < 0) {
|
||||
at = array->count + at + 1;
|
||||
}
|
||||
if (at < 0 || at > array->count)
|
||||
janet_panicf("removal index %d out of range [0,%d]", at, array->count);
|
||||
if (argc == 3) {
|
||||
n = janet_getinteger(argv, 2);
|
||||
if (n < 0)
|
||||
janet_panicf("expected non-negative integer for argument n, got %v", argv[2]);
|
||||
}
|
||||
if (at + n > array->count) {
|
||||
n = array->count - at;
|
||||
}
|
||||
memmove(array->data + at,
|
||||
array->data + at + n,
|
||||
(array->count - at - n) * sizeof(Janet));
|
||||
array->count -= n;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_array_trim,
|
||||
"(array/trim arr)",
|
||||
"Set the backing capacity of an array to its current length. Returns the modified array.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
if (array->count) {
|
||||
if (array->count < array->capacity) {
|
||||
Janet *newData = janet_realloc(array->data, array->count * sizeof(Janet));
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
array->data = newData;
|
||||
array->capacity = array->count;
|
||||
}
|
||||
} else {
|
||||
array->capacity = 0;
|
||||
janet_free(array->data);
|
||||
array->data = NULL;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_array_clear,
|
||||
"(array/clear arr)",
|
||||
"Empties an array, setting it's count to 0 but does not free the backing capacity. "
|
||||
"Returns the modified array.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
array->count = 0;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
/* Load the array module */
|
||||
void janet_lib_array(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, array_cfuns);
|
||||
JanetRegExt array_cfuns[] = {
|
||||
JANET_CORE_REG("array/new", cfun_array_new),
|
||||
JANET_CORE_REG("array/new-filled", cfun_array_new_filled),
|
||||
JANET_CORE_REG("array/fill", cfun_array_fill),
|
||||
JANET_CORE_REG("array/pop", cfun_array_pop),
|
||||
JANET_CORE_REG("array/peek", cfun_array_peek),
|
||||
JANET_CORE_REG("array/push", cfun_array_push),
|
||||
JANET_CORE_REG("array/ensure", cfun_array_ensure),
|
||||
JANET_CORE_REG("array/slice", cfun_array_slice),
|
||||
JANET_CORE_REG("array/concat", cfun_array_concat),
|
||||
JANET_CORE_REG("array/insert", cfun_array_insert),
|
||||
JANET_CORE_REG("array/remove", cfun_array_remove),
|
||||
JANET_CORE_REG("array/trim", cfun_array_trim),
|
||||
JANET_CORE_REG("array/clear", cfun_array_clear),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, array_cfuns);
|
||||
}
|
||||
|
||||
627
src/core/asm.c
627
src/core/asm.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,19 +21,28 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
/* Allow for managed buffers that cannot realloc/free their backing memory */
|
||||
static void janet_buffer_can_realloc(JanetBuffer *buffer) {
|
||||
if (buffer->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC) {
|
||||
janet_panic("buffer cannot reallocate foreign memory");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize a buffer */
|
||||
JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
|
||||
static JanetBuffer *janet_buffer_init_impl(JanetBuffer *buffer, int32_t capacity) {
|
||||
uint8_t *data = NULL;
|
||||
if (capacity > 0) {
|
||||
data = malloc(sizeof(uint8_t) * capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
if (capacity < 4) capacity = 4;
|
||||
janet_gcpressure(capacity);
|
||||
data = janet_malloc(sizeof(uint8_t) * (size_t) capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
buffer->count = 0;
|
||||
buffer->capacity = capacity;
|
||||
@@ -41,15 +50,37 @@ JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Initialize a buffer */
|
||||
JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
|
||||
janet_buffer_init_impl(buffer, capacity);
|
||||
buffer->gc.data.next = NULL;
|
||||
buffer->gc.flags = JANET_MEM_DISABLED;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Initialize an unmanaged buffer */
|
||||
JanetBuffer *janet_pointer_buffer_unsafe(void *memory, int32_t capacity, int32_t count) {
|
||||
if (count < 0) janet_panic("count < 0");
|
||||
if (capacity < count) janet_panic("capacity < count");
|
||||
JanetBuffer *buffer = janet_gcalloc(JANET_MEMORY_BUFFER, sizeof(JanetBuffer));
|
||||
buffer->gc.flags |= JANET_BUFFER_FLAG_NO_REALLOC;
|
||||
buffer->capacity = capacity;
|
||||
buffer->count = count;
|
||||
buffer->data = (uint8_t *) memory;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Deinitialize a buffer (free data memory) */
|
||||
void janet_buffer_deinit(JanetBuffer *buffer) {
|
||||
free(buffer->data);
|
||||
if (!(buffer->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC)) {
|
||||
janet_free(buffer->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize a buffer */
|
||||
JanetBuffer *janet_buffer(int32_t capacity) {
|
||||
JanetBuffer *buffer = janet_gcalloc(JANET_MEMORY_BUFFER, sizeof(JanetBuffer));
|
||||
return janet_buffer_init(buffer, capacity);
|
||||
return janet_buffer_init_impl(buffer, capacity);
|
||||
}
|
||||
|
||||
/* Ensure that the buffer has enough internal capacity */
|
||||
@@ -57,9 +88,11 @@ void janet_buffer_ensure(JanetBuffer *buffer, int32_t capacity, int32_t growth)
|
||||
uint8_t *new_data;
|
||||
uint8_t *old = buffer->data;
|
||||
if (capacity <= buffer->capacity) return;
|
||||
int64_t big_capacity = capacity * growth;
|
||||
janet_buffer_can_realloc(buffer);
|
||||
int64_t big_capacity = ((int64_t) capacity) * growth;
|
||||
capacity = big_capacity > INT32_MAX ? INT32_MAX : (int32_t) big_capacity;
|
||||
new_data = realloc(old, capacity * sizeof(uint8_t));
|
||||
janet_gcpressure(capacity - buffer->capacity);
|
||||
new_data = janet_realloc(old, (size_t) capacity * sizeof(uint8_t));
|
||||
if (NULL == new_data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -88,8 +121,10 @@ void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
|
||||
}
|
||||
int32_t new_size = buffer->count + n;
|
||||
if (new_size > buffer->capacity) {
|
||||
int32_t new_capacity = new_size * 2;
|
||||
uint8_t *new_data = realloc(buffer->data, new_capacity * sizeof(uint8_t));
|
||||
janet_buffer_can_realloc(buffer);
|
||||
int32_t new_capacity = (new_size > (INT32_MAX / 2)) ? INT32_MAX : (new_size * 2);
|
||||
uint8_t *new_data = janet_realloc(buffer->data, new_capacity * sizeof(uint8_t));
|
||||
janet_gcpressure(new_capacity - buffer->capacity);
|
||||
if (NULL == new_data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -107,6 +142,7 @@ void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
|
||||
|
||||
/* Push multiple bytes into the buffer */
|
||||
void janet_buffer_push_bytes(JanetBuffer *buffer, const uint8_t *string, int32_t length) {
|
||||
if (0 == length) return;
|
||||
janet_buffer_extra(buffer, length);
|
||||
memcpy(buffer->data + buffer->count, string, length);
|
||||
buffer->count += length;
|
||||
@@ -157,37 +193,87 @@ void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
|
||||
|
||||
/* C functions */
|
||||
|
||||
static Janet cfun_buffer_new(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_new,
|
||||
"(buffer/new capacity)",
|
||||
"Creates a new, empty buffer with enough backing memory for `capacity` bytes. "
|
||||
"Returns a new buffer of length 0.") {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
JanetBuffer *buffer = janet_buffer(cap);
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_new_filled(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_new_filled,
|
||||
"(buffer/new-filled count &opt byte)",
|
||||
"Creates a new buffer of length `count` filled with `byte`. By default, `byte` is 0. "
|
||||
"Returns the new buffer.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t count = janet_getinteger(argv, 0);
|
||||
if (count < 0) count = 0;
|
||||
int32_t byte = 0;
|
||||
if (argc == 2) {
|
||||
byte = janet_getinteger(argv, 1) & 0xFF;
|
||||
}
|
||||
JanetBuffer *buffer = janet_buffer(count);
|
||||
memset(buffer->data, byte, count);
|
||||
if (buffer->data && count > 0)
|
||||
memset(buffer->data, byte, count);
|
||||
buffer->count = count;
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_u8(int32_t argc, Janet *argv) {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JANET_CORE_FN(cfun_buffer_fill,
|
||||
"(buffer/fill buffer &opt byte)",
|
||||
"Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. "
|
||||
"Returns the modified buffer.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
janet_buffer_push_u8(buffer, (uint8_t) (janet_getinteger(argv, i) & 0xFF));
|
||||
int32_t byte = 0;
|
||||
if (argc == 2) {
|
||||
byte = janet_getinteger(argv, 1) & 0xFF;
|
||||
}
|
||||
if (buffer->count) {
|
||||
memset(buffer->data, byte, buffer->count);
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_trim,
|
||||
"(buffer/trim buffer)",
|
||||
"Set the backing capacity of the buffer to the current length of the buffer. Returns the "
|
||||
"modified buffer.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
janet_buffer_can_realloc(buffer);
|
||||
if (buffer->count < buffer->capacity) {
|
||||
int32_t newcap = buffer->count > 4 ? buffer->count : 4;
|
||||
uint8_t *newData = janet_realloc(buffer->data, newcap);
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
buffer->data = newData;
|
||||
buffer->capacity = newcap;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_u8,
|
||||
"(buffer/push-byte buffer & xs)",
|
||||
"Append bytes to a buffer. Will expand the buffer as necessary. "
|
||||
"Returns the modified buffer. Will throw an error if the buffer overflows.") {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
janet_buffer_push_u8(buffer, (uint8_t)(janet_getinteger(argv, i) & 0xFF));
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_word,
|
||||
"(buffer/push-word buffer & xs)",
|
||||
"Append machine words to a buffer. The 4 bytes of the integer are appended "
|
||||
"in twos complement, little endian order, unsigned for all x. Returns the modified buffer. Will "
|
||||
"throw an error if the buffer overflows.") {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
@@ -201,25 +287,86 @@ static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_chars(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_chars,
|
||||
"(buffer/push-string buffer & xs)",
|
||||
"Push byte sequences onto the end of a buffer. "
|
||||
"Will accept any of strings, keywords, symbols, and buffers. "
|
||||
"Returns the modified buffer. "
|
||||
"Will throw an error if the buffer overflows.") {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
JanetByteView view = janet_getbytes(argv, i);
|
||||
if (view.bytes == buffer->data) {
|
||||
janet_buffer_ensure(buffer, buffer->count + view.len, 2);
|
||||
view.bytes = buffer->data;
|
||||
}
|
||||
janet_buffer_push_bytes(buffer, view.bytes, view.len);
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_clear(int32_t argc, Janet *argv) {
|
||||
static void buffer_push_impl(JanetBuffer *buffer, Janet *argv, int32_t argc_offset, int32_t argc) {
|
||||
for (int32_t i = argc_offset; i < argc; i++) {
|
||||
if (janet_checktype(argv[i], JANET_NUMBER)) {
|
||||
janet_buffer_push_u8(buffer, (uint8_t)(janet_getinteger(argv, i) & 0xFF));
|
||||
} else {
|
||||
JanetByteView view = janet_getbytes(argv, i);
|
||||
if (view.bytes == buffer->data) {
|
||||
janet_buffer_ensure(buffer, buffer->count + view.len, 2);
|
||||
view.bytes = buffer->data;
|
||||
}
|
||||
janet_buffer_push_bytes(buffer, view.bytes, view.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_push_at,
|
||||
"(buffer/push-at buffer index & xs)",
|
||||
"Same as buffer/push, but copies the new data into the buffer "
|
||||
" at index `index`.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int32_t index = janet_getinteger(argv, 1);
|
||||
int32_t old_count = buffer->count;
|
||||
if (index < 0 || index > old_count) {
|
||||
janet_panicf("index out of range [0, %d)", old_count);
|
||||
}
|
||||
buffer->count = index;
|
||||
buffer_push_impl(buffer, argv, 2, argc);
|
||||
if (buffer->count < old_count) {
|
||||
buffer->count = old_count;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_push,
|
||||
"(buffer/push buffer & xs)",
|
||||
"Push both individual bytes and byte sequences to a buffer. For each x in xs, "
|
||||
"push the byte if x is an integer, otherwise push the bytesequence to the buffer. "
|
||||
"Thus, this function behaves like both `buffer/push-string` and `buffer/push-byte`. "
|
||||
"Returns the modified buffer. "
|
||||
"Will throw an error if the buffer overflows.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
buffer_push_impl(buffer, argv, 1, argc);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_clear,
|
||||
"(buffer/clear buffer)",
|
||||
"Sets the size of a buffer to 0 and empties it. The buffer retains "
|
||||
"its memory so it can be efficiently refilled. Returns the modified buffer.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
buffer->count = 0;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_popn(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_popn,
|
||||
"(buffer/popn buffer n)",
|
||||
"Removes the last `n` bytes from the buffer. Returns the modified buffer.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int32_t n = janet_getinteger(argv, 1);
|
||||
@@ -232,11 +379,17 @@ static Janet cfun_buffer_popn(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_slice(int32_t argc, Janet *argv) {
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JANET_CORE_FN(cfun_buffer_slice,
|
||||
"(buffer/slice bytes &opt start end)",
|
||||
"Takes a slice of a byte sequence from `start` to `end`. The range is half open, "
|
||||
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
|
||||
"end of the array. By default, `start` is 0 and `end` is the length of the buffer. "
|
||||
"Returns a new buffer.") {
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JanetBuffer *buffer = janet_buffer(range.end - range.start);
|
||||
memcpy(buffer->data, view.bytes + range.start, range.end - range.start);
|
||||
if (buffer->data)
|
||||
memcpy(buffer->data, view.bytes + range.start, range.end - range.start);
|
||||
buffer->count = range.end - range.start;
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
@@ -255,7 +408,9 @@ static void bitloc(int32_t argc, Janet *argv, JanetBuffer **b, int32_t *index, i
|
||||
*bit = which_bit;
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_bitset,
|
||||
"(buffer/bit-set buffer index)",
|
||||
"Sets the bit at the given bit-index. Returns the buffer.") {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
@@ -264,7 +419,9 @@ static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_bitclear,
|
||||
"(buffer/bit-clear buffer index)",
|
||||
"Clears the bit at the given bit-index. Returns the buffer.") {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
@@ -273,7 +430,9 @@ static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_bitget,
|
||||
"(buffer/bit buffer index)",
|
||||
"Gets the bit at the given bit-index. Returns true if the bit is set, false if not.") {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
@@ -281,7 +440,9 @@ static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_boolean(buffer->data[index] & (1 << bit));
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_bittoggle,
|
||||
"(buffer/bit-toggle buffer index)",
|
||||
"Toggles the bit at the given bit index in buffer. Returns the buffer.") {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
@@ -290,10 +451,15 @@ static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_buffer_blit,
|
||||
"(buffer/blit dest src &opt dest-start src-start src-end)",
|
||||
"Insert the contents of `src` into `dest`. Can optionally take indices that "
|
||||
"indicate which part of `src` to copy into which part of `dest`. Indices can be "
|
||||
"negative in order to index from the end of `src` or `dest`. Returns `dest`.") {
|
||||
janet_arity(argc, 2, 5);
|
||||
JanetBuffer *dest = janet_getbuffer(argv, 0);
|
||||
JanetByteView src = janet_getbytes(argv, 1);
|
||||
int same_buf = src.bytes == dest->data;
|
||||
int32_t offset_dest = 0;
|
||||
int32_t offset_src = 0;
|
||||
if (argc > 2)
|
||||
@@ -308,84 +474,56 @@ static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
|
||||
} else {
|
||||
length_src = src.len - offset_src;
|
||||
}
|
||||
int64_t last = ((int64_t) offset_dest - offset_src) + length_src;
|
||||
int64_t last = (int64_t) offset_dest + length_src;
|
||||
if (last > INT32_MAX)
|
||||
janet_panic("buffer blit out of range");
|
||||
janet_buffer_ensure(dest, (int32_t) last, 2);
|
||||
if (last > dest->count) dest->count = (int32_t) last;
|
||||
memcpy(dest->data + offset_dest, src.bytes + offset_src, length_src);
|
||||
int32_t last32 = (int32_t) last;
|
||||
janet_buffer_ensure(dest, last32, 2);
|
||||
if (last32 > dest->count) dest->count = last32;
|
||||
if (length_src) {
|
||||
if (same_buf) {
|
||||
/* janet_buffer_ensure may have invalidated src */
|
||||
src.bytes = dest->data;
|
||||
memmove(dest->data + offset_dest, src.bytes + offset_src, length_src);
|
||||
} else {
|
||||
memcpy(dest->data + offset_dest, src.bytes + offset_src, length_src);
|
||||
}
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg buffer_cfuns[] = {
|
||||
{"buffer/new", cfun_buffer_new,
|
||||
JDOC("(buffer/new capacity)\n\n"
|
||||
"Creates a new, empty buffer with enough memory for capacity bytes. "
|
||||
"Returns a new buffer.")
|
||||
},
|
||||
{"buffer/new-filled", cfun_buffer_new_filled,
|
||||
JDOC("(buffer/new-filled count [, byte=0])\n\n"
|
||||
"Creates a new buffer of length count filled with byte. "
|
||||
"Returns the new buffer.")
|
||||
},
|
||||
{"buffer/push-byte", cfun_buffer_u8,
|
||||
JDOC("(buffer/push-byte buffer x)\n\n"
|
||||
"Append a byte to a buffer. Will expand the buffer as necessary. "
|
||||
"Returns the modified buffer. Will throw an error if the buffer overflows.")
|
||||
},
|
||||
{"buffer/push-word", cfun_buffer_word,
|
||||
JDOC("(buffer/push-word buffer x)\n\n"
|
||||
"Append a machine word to a buffer. The 4 bytes of the integer are appended "
|
||||
"in twos complement, big endian order, unsigned. Returns the modified buffer. Will "
|
||||
"throw an error if the buffer overflows.")
|
||||
},
|
||||
{"buffer/push-string", cfun_buffer_chars,
|
||||
JDOC("(buffer/push-string buffer str)\n\n"
|
||||
"Push a string onto the end of a buffer. Non string values will be converted "
|
||||
"to strings before being pushed. Returns the modified buffer. "
|
||||
"Will throw an error if the buffer overflows.")
|
||||
},
|
||||
{"buffer/popn", cfun_buffer_popn,
|
||||
JDOC("(buffer/popn buffer n)\n\n"
|
||||
"Removes the last n bytes from the buffer. Returns the modified buffer.")
|
||||
},
|
||||
{"buffer/clear", cfun_buffer_clear,
|
||||
JDOC("(buffer/clear buffer)\n\n"
|
||||
"Sets the size of a buffer to 0 and empties it. The buffer retains "
|
||||
"its memory so it can be efficiently refilled. Returns the modified buffer.")
|
||||
},
|
||||
{"buffer/slice", cfun_buffer_slice,
|
||||
JDOC("(buffer/slice bytes [, start=0 [, end=(length bytes)]])\n\n"
|
||||
"Takes a slice of a byte sequence from start to end. The range is half open, "
|
||||
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
|
||||
"end of the array. By default, start is 0 and end is the length of the buffer. "
|
||||
"Returns a new buffer.")
|
||||
},
|
||||
{"buffer/bit-set", cfun_buffer_bitset,
|
||||
JDOC("(buffer/bit-set buffer index)\n\n"
|
||||
"Sets the bit at the given bit-index. Returns the buffer.")
|
||||
},
|
||||
{"buffer/bit-clear", cfun_buffer_bitclear,
|
||||
JDOC("(buffer/bit-clear buffer index)\n\n"
|
||||
"Clears the bit at the given bit-index. Returns the buffer.")
|
||||
},
|
||||
{"buffer/bit", cfun_buffer_bitget,
|
||||
JDOC("(buffer/bit buffer index)\n\n"
|
||||
"Gets the bit at the given bit-index. Returns true if the bit is set, false if not.")
|
||||
},
|
||||
{"buffer/bit-toggle", cfun_buffer_bittoggle,
|
||||
JDOC("(buffer/bit-toggle buffer index)\n\n"
|
||||
"Toggles the bit at the given bit index in buffer. Returns the buffer.")
|
||||
},
|
||||
{"buffer/blit", cfun_buffer_blit,
|
||||
JDOC("(buffer/blit dest src [, dest-start=0 [, src-start=0 [, src-end=-1]]])\n\n"
|
||||
"Insert the contents of src into dest. Can optionally take indices that "
|
||||
"indicate which part of src to copy into which part of dest. Indices can be "
|
||||
"negative to index from the end of src or dest. Returns dest.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
JANET_CORE_FN(cfun_buffer_format,
|
||||
"(buffer/format buffer format & args)",
|
||||
"Snprintf like functionality for printing values into a buffer. Returns "
|
||||
"the modified buffer.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
const char *strfrmt = (const char *) janet_getstring(argv, 1);
|
||||
janet_buffer_format(buffer, strfrmt, 1, argc, argv);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
void janet_lib_buffer(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, buffer_cfuns);
|
||||
JanetRegExt buffer_cfuns[] = {
|
||||
JANET_CORE_REG("buffer/new", cfun_buffer_new),
|
||||
JANET_CORE_REG("buffer/new-filled", cfun_buffer_new_filled),
|
||||
JANET_CORE_REG("buffer/fill", cfun_buffer_fill),
|
||||
JANET_CORE_REG("buffer/trim", cfun_buffer_trim),
|
||||
JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8),
|
||||
JANET_CORE_REG("buffer/push-word", cfun_buffer_word),
|
||||
JANET_CORE_REG("buffer/push-string", cfun_buffer_chars),
|
||||
JANET_CORE_REG("buffer/push", cfun_buffer_push),
|
||||
JANET_CORE_REG("buffer/push-at", cfun_buffer_push_at),
|
||||
JANET_CORE_REG("buffer/popn", cfun_buffer_popn),
|
||||
JANET_CORE_REG("buffer/clear", cfun_buffer_clear),
|
||||
JANET_CORE_REG("buffer/slice", cfun_buffer_slice),
|
||||
JANET_CORE_REG("buffer/bit-set", cfun_buffer_bitset),
|
||||
JANET_CORE_REG("buffer/bit-clear", cfun_buffer_bitclear),
|
||||
JANET_CORE_REG("buffer/bit", cfun_buffer_bitget),
|
||||
JANET_CORE_REG("buffer/bit-toggle", cfun_buffer_bittoggle),
|
||||
JANET_CORE_REG("buffer/blit", cfun_buffer_blit),
|
||||
JANET_CORE_REG("buffer/format", cfun_buffer_format),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, buffer_cfuns);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,8 +21,11 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include "regalloc.h"
|
||||
#endif
|
||||
|
||||
/* Look up table for instructions */
|
||||
@@ -34,11 +37,15 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
|
||||
JINT_0, /* JOP_RETURN_NIL, */
|
||||
JINT_SSI, /* JOP_ADD_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_ADD, */
|
||||
JINT_SSI, /* JOP_SUBTRACT_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_SUBTRACT, */
|
||||
JINT_SSI, /* JOP_MULTIPLY_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_MULTIPLY, */
|
||||
JINT_SSI, /* JOP_DIVIDE_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_DIVIDE, */
|
||||
JINT_SSS, /* JOP_DIVIDE_FLOOR */
|
||||
JINT_SSS, /* JOP_MODULO, */
|
||||
JINT_SSS, /* JOP_REMAINDER, */
|
||||
JINT_SSS, /* JOP_BAND, */
|
||||
JINT_SSS, /* JOP_BOR, */
|
||||
JINT_SSS, /* JOP_BXOR, */
|
||||
@@ -54,6 +61,8 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
|
||||
JINT_L, /* JOP_JUMP, */
|
||||
JINT_SL, /* JOP_JUMP_IF, */
|
||||
JINT_SL, /* JOP_JUMP_IF_NOT, */
|
||||
JINT_SL, /* JOP_JUMP_IF_NIL, */
|
||||
JINT_SL, /* JOP_JUMP_IF_NOT_NIL, */
|
||||
JINT_SSS, /* JOP_GREATER_THAN, */
|
||||
JINT_SSI, /* JOP_GREATER_THAN_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_LESS_THAN, */
|
||||
@@ -78,6 +87,8 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
|
||||
JINT_S, /* JOP_TAILCALL, */
|
||||
JINT_SSS, /* JOP_RESUME, */
|
||||
JINT_SSU, /* JOP_SIGNAL, */
|
||||
JINT_SSS, /* JOP_PROPAGATE */
|
||||
JINT_SSS, /* JOP_IN, */
|
||||
JINT_SSS, /* JOP_GET, */
|
||||
JINT_SSS, /* JOP_PUT, */
|
||||
JINT_SSU, /* JOP_GET_INDEX, */
|
||||
@@ -85,19 +96,306 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
|
||||
JINT_SS, /* JOP_LENGTH */
|
||||
JINT_S, /* JOP_MAKE_ARRAY */
|
||||
JINT_S, /* JOP_MAKE_BUFFER */
|
||||
JINT_S, /* JOP_MAKE_TUPLE */
|
||||
JINT_S, /* JOP_MAKE_STRING */
|
||||
JINT_S, /* JOP_MAKE_STRUCT */
|
||||
JINT_S, /* JOP_MAKE_TABLE */
|
||||
JINT_S, /* JOP_MAKE_STRING */
|
||||
JINT_SSS, /* JOP_NUMERIC_LESS_THAN */
|
||||
JINT_SSS, /* JOP_NUMERIC_LESS_THAN_EQUAL */
|
||||
JINT_SSS, /* JOP_NUMERIC_GREATER_THAN */
|
||||
JINT_SSS, /* JOP_NUMERIC_GREATER_THAN_EQUAL */
|
||||
JINT_SSS /* JOP_NUMERIC_EQUAL */
|
||||
JINT_S, /* JOP_MAKE_TUPLE */
|
||||
JINT_S, /* JOP_MAKE_BRACKET_TUPLE */
|
||||
JINT_SSS, /* JOP_GREATER_THAN_EQUAL */
|
||||
JINT_SSS, /* JOP_LESS_THAN_EQUAL */
|
||||
JINT_SSS, /* JOP_NEXT */
|
||||
JINT_SSS, /* JOP_NOT_EQUALS, */
|
||||
JINT_SSI, /* JOP_NOT_EQUALS_IMMEDIATE, */
|
||||
JINT_SSS /* JOP_CANCEL, */
|
||||
};
|
||||
|
||||
/* Remove all noops while preserving jumps and debugging information.
|
||||
* Useful as part of a filtering compiler pass. */
|
||||
void janet_bytecode_remove_noops(JanetFuncDef *def) {
|
||||
|
||||
/* Get an instruction rewrite map so we can rewrite jumps */
|
||||
uint32_t *pc_map = janet_smalloc(sizeof(uint32_t) * (1 + def->bytecode_length));
|
||||
uint32_t new_bytecode_length = 0;
|
||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
||||
uint32_t instr = def->bytecode[i];
|
||||
uint32_t opcode = instr & 0x7F;
|
||||
pc_map[i] = new_bytecode_length;
|
||||
if (opcode != JOP_NOOP) {
|
||||
new_bytecode_length++;
|
||||
}
|
||||
}
|
||||
pc_map[def->bytecode_length] = new_bytecode_length;
|
||||
|
||||
/* Linear scan rewrite bytecode and sourcemap. Also fix jumps. */
|
||||
int32_t j = 0;
|
||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
||||
uint32_t instr = def->bytecode[i];
|
||||
uint32_t opcode = instr & 0x7F;
|
||||
int32_t old_jump_target = 0;
|
||||
int32_t new_jump_target = 0;
|
||||
switch (opcode) {
|
||||
case JOP_NOOP:
|
||||
continue;
|
||||
case JOP_JUMP:
|
||||
/* relative pc is in DS field of instruction */
|
||||
old_jump_target = i + (((int32_t)instr) >> 8);
|
||||
new_jump_target = pc_map[old_jump_target];
|
||||
instr += (new_jump_target - old_jump_target + (i - j)) << 8;
|
||||
break;
|
||||
case JOP_JUMP_IF:
|
||||
case JOP_JUMP_IF_NIL:
|
||||
case JOP_JUMP_IF_NOT:
|
||||
case JOP_JUMP_IF_NOT_NIL:
|
||||
/* relative pc is in ES field of instruction */
|
||||
old_jump_target = i + (((int32_t)instr) >> 16);
|
||||
new_jump_target = pc_map[old_jump_target];
|
||||
instr += (new_jump_target - old_jump_target + (i - j)) << 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
def->bytecode[j] = instr;
|
||||
if (def->sourcemap != NULL) {
|
||||
def->sourcemap[j] = def->sourcemap[i];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
/* Rewrite symbolmap */
|
||||
for (int32_t i = 0; i < def->symbolmap_length; i++) {
|
||||
JanetSymbolMap *sm = def->symbolmap + i;
|
||||
/* Don't rewrite upvalue mappings */
|
||||
if (sm->birth_pc < UINT32_MAX) {
|
||||
sm->birth_pc = pc_map[sm->birth_pc];
|
||||
sm->death_pc = pc_map[sm->death_pc];
|
||||
}
|
||||
}
|
||||
|
||||
def->bytecode_length = new_bytecode_length;
|
||||
def->bytecode = janet_realloc(def->bytecode, def->bytecode_length * sizeof(uint32_t));
|
||||
janet_sfree(pc_map);
|
||||
}
|
||||
|
||||
/* Remove redundant loads, moves and other instructions if possible and convert them to
|
||||
* noops. Input is assumed valid bytecode. */
|
||||
void janet_bytecode_movopt(JanetFuncDef *def) {
|
||||
JanetcRegisterAllocator ra;
|
||||
int recur = 1;
|
||||
|
||||
/* Iterate this until no more instructions can be removed. */
|
||||
while (recur) {
|
||||
janetc_regalloc_init(&ra);
|
||||
|
||||
/* Look for slots that have writes but no reads (and aren't in the closure bitset). */
|
||||
if (def->closure_bitset != NULL) {
|
||||
for (int32_t i = 0; i < def->slotcount; i++) {
|
||||
int32_t index = i >> 5;
|
||||
uint32_t mask = 1U << (((uint32_t) i) & 31);
|
||||
if (def->closure_bitset[index] & mask) {
|
||||
janetc_regalloc_touch(&ra, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define AA ((instr >> 8) & 0xFF)
|
||||
#define BB ((instr >> 16) & 0xFF)
|
||||
#define CC (instr >> 24)
|
||||
#define DD (instr >> 8)
|
||||
#define EE (instr >> 16)
|
||||
|
||||
/* Check reads and writes */
|
||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
||||
uint32_t instr = def->bytecode[i];
|
||||
switch (instr & 0x7F) {
|
||||
|
||||
/* Group instructions my how they read from slots */
|
||||
|
||||
/* No reads or writes */
|
||||
default:
|
||||
janet_assert(0, "unhandled instruction");
|
||||
case JOP_JUMP:
|
||||
case JOP_NOOP:
|
||||
case JOP_RETURN_NIL:
|
||||
/* Write A */
|
||||
case JOP_LOAD_INTEGER:
|
||||
case JOP_LOAD_CONSTANT:
|
||||
case JOP_LOAD_UPVALUE:
|
||||
case JOP_CLOSURE:
|
||||
/* Write D */
|
||||
case JOP_LOAD_NIL:
|
||||
case JOP_LOAD_TRUE:
|
||||
case JOP_LOAD_FALSE:
|
||||
case JOP_LOAD_SELF:
|
||||
case JOP_MAKE_ARRAY:
|
||||
case JOP_MAKE_BUFFER:
|
||||
case JOP_MAKE_STRING:
|
||||
case JOP_MAKE_STRUCT:
|
||||
case JOP_MAKE_TABLE:
|
||||
case JOP_MAKE_TUPLE:
|
||||
case JOP_MAKE_BRACKET_TUPLE:
|
||||
break;
|
||||
|
||||
/* Read A */
|
||||
case JOP_ERROR:
|
||||
case JOP_TYPECHECK:
|
||||
case JOP_JUMP_IF:
|
||||
case JOP_JUMP_IF_NOT:
|
||||
case JOP_JUMP_IF_NIL:
|
||||
case JOP_JUMP_IF_NOT_NIL:
|
||||
case JOP_SET_UPVALUE:
|
||||
/* Write E, Read A */
|
||||
case JOP_MOVE_FAR:
|
||||
janetc_regalloc_touch(&ra, AA);
|
||||
break;
|
||||
|
||||
/* Read B */
|
||||
case JOP_SIGNAL:
|
||||
/* Write A, Read B */
|
||||
case JOP_ADD_IMMEDIATE:
|
||||
case JOP_SUBTRACT_IMMEDIATE:
|
||||
case JOP_MULTIPLY_IMMEDIATE:
|
||||
case JOP_DIVIDE_IMMEDIATE:
|
||||
case JOP_SHIFT_LEFT_IMMEDIATE:
|
||||
case JOP_SHIFT_RIGHT_IMMEDIATE:
|
||||
case JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE:
|
||||
case JOP_GREATER_THAN_IMMEDIATE:
|
||||
case JOP_LESS_THAN_IMMEDIATE:
|
||||
case JOP_EQUALS_IMMEDIATE:
|
||||
case JOP_NOT_EQUALS_IMMEDIATE:
|
||||
case JOP_GET_INDEX:
|
||||
janetc_regalloc_touch(&ra, BB);
|
||||
break;
|
||||
|
||||
/* Read D */
|
||||
case JOP_RETURN:
|
||||
case JOP_PUSH:
|
||||
case JOP_PUSH_ARRAY:
|
||||
case JOP_TAILCALL:
|
||||
janetc_regalloc_touch(&ra, DD);
|
||||
break;
|
||||
|
||||
/* Write A, Read E */
|
||||
case JOP_MOVE_NEAR:
|
||||
case JOP_LENGTH:
|
||||
case JOP_BNOT:
|
||||
case JOP_CALL:
|
||||
janetc_regalloc_touch(&ra, EE);
|
||||
break;
|
||||
|
||||
/* Read A, B */
|
||||
case JOP_PUT_INDEX:
|
||||
janetc_regalloc_touch(&ra, AA);
|
||||
janetc_regalloc_touch(&ra, BB);
|
||||
break;
|
||||
|
||||
/* Read A, E */
|
||||
case JOP_PUSH_2:
|
||||
janetc_regalloc_touch(&ra, AA);
|
||||
janetc_regalloc_touch(&ra, EE);
|
||||
break;
|
||||
|
||||
/* Read B, C */
|
||||
case JOP_PROPAGATE:
|
||||
/* Write A, Read B and C */
|
||||
case JOP_BAND:
|
||||
case JOP_BOR:
|
||||
case JOP_BXOR:
|
||||
case JOP_ADD:
|
||||
case JOP_SUBTRACT:
|
||||
case JOP_MULTIPLY:
|
||||
case JOP_DIVIDE:
|
||||
case JOP_DIVIDE_FLOOR:
|
||||
case JOP_MODULO:
|
||||
case JOP_REMAINDER:
|
||||
case JOP_SHIFT_LEFT:
|
||||
case JOP_SHIFT_RIGHT:
|
||||
case JOP_SHIFT_RIGHT_UNSIGNED:
|
||||
case JOP_GREATER_THAN:
|
||||
case JOP_LESS_THAN:
|
||||
case JOP_EQUALS:
|
||||
case JOP_COMPARE:
|
||||
case JOP_IN:
|
||||
case JOP_GET:
|
||||
case JOP_GREATER_THAN_EQUAL:
|
||||
case JOP_LESS_THAN_EQUAL:
|
||||
case JOP_NOT_EQUALS:
|
||||
case JOP_CANCEL:
|
||||
case JOP_RESUME:
|
||||
case JOP_NEXT:
|
||||
janetc_regalloc_touch(&ra, BB);
|
||||
janetc_regalloc_touch(&ra, CC);
|
||||
break;
|
||||
|
||||
/* Read A, B, C */
|
||||
case JOP_PUT:
|
||||
case JOP_PUSH_3:
|
||||
janetc_regalloc_touch(&ra, AA);
|
||||
janetc_regalloc_touch(&ra, BB);
|
||||
janetc_regalloc_touch(&ra, CC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate and set noops on instructions that make writes that no one ever reads.
|
||||
* Only set noops for instructions with no side effects - moves, loads, etc. that can't
|
||||
* raise errors (outside of systemic errors like oom or stack overflow). */
|
||||
recur = 0;
|
||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
||||
uint32_t instr = def->bytecode[i];
|
||||
switch (instr & 0x7F) {
|
||||
default:
|
||||
break;
|
||||
/* Write D */
|
||||
case JOP_LOAD_NIL:
|
||||
case JOP_LOAD_TRUE:
|
||||
case JOP_LOAD_FALSE:
|
||||
case JOP_LOAD_SELF:
|
||||
case JOP_MAKE_ARRAY:
|
||||
case JOP_MAKE_TUPLE:
|
||||
case JOP_MAKE_BRACKET_TUPLE: {
|
||||
if (!janetc_regalloc_check(&ra, DD)) {
|
||||
def->bytecode[i] = JOP_NOOP;
|
||||
recur = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Write E, Read A */
|
||||
case JOP_MOVE_FAR: {
|
||||
if (!janetc_regalloc_check(&ra, EE)) {
|
||||
def->bytecode[i] = JOP_NOOP;
|
||||
recur = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Write A, Read E */
|
||||
case JOP_MOVE_NEAR:
|
||||
/* Write A, Read B */
|
||||
case JOP_GET_INDEX:
|
||||
/* Write A */
|
||||
case JOP_LOAD_INTEGER:
|
||||
case JOP_LOAD_CONSTANT:
|
||||
case JOP_LOAD_UPVALUE:
|
||||
case JOP_CLOSURE: {
|
||||
if (!janetc_regalloc_check(&ra, AA)) {
|
||||
def->bytecode[i] = JOP_NOOP;
|
||||
recur = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
janetc_regalloc_deinit(&ra);
|
||||
#undef AA
|
||||
#undef BB
|
||||
#undef CC
|
||||
#undef DD
|
||||
#undef EE
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify some bytecode */
|
||||
int32_t janet_verify(JanetFuncDef *def) {
|
||||
int janet_verify(JanetFuncDef *def) {
|
||||
int vargs = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG);
|
||||
int32_t i;
|
||||
int32_t maxslot = def->arity + vargs;
|
||||
@@ -118,72 +416,62 @@ int32_t janet_verify(JanetFuncDef *def) {
|
||||
switch (type) {
|
||||
case JINT_0:
|
||||
continue;
|
||||
case JINT_S:
|
||||
{
|
||||
if ((int32_t)(instr >> 8) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
case JINT_S: {
|
||||
if ((int32_t)(instr >> 8) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
case JINT_SI:
|
||||
case JINT_SU:
|
||||
case JINT_ST:
|
||||
{
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
case JINT_L:
|
||||
{
|
||||
int32_t jumpdest = i + (((int32_t)instr) >> 8);
|
||||
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
|
||||
continue;
|
||||
}
|
||||
case JINT_SS:
|
||||
{
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
|
||||
case JINT_ST: {
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
case JINT_L: {
|
||||
int32_t jumpdest = i + (((int32_t)instr) >> 8);
|
||||
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
|
||||
continue;
|
||||
}
|
||||
case JINT_SS: {
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
|
||||
(int32_t)(instr >> 16) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case JINT_SSI:
|
||||
case JINT_SSU:
|
||||
{
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
|
||||
case JINT_SSU: {
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
|
||||
(int32_t)((instr >> 16) & 0xFF) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
case JINT_SL:
|
||||
{
|
||||
int32_t jumpdest = i + (((int32_t)instr) >> 16);
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
|
||||
continue;
|
||||
}
|
||||
case JINT_SSS:
|
||||
{
|
||||
if (((int32_t)(instr >> 8) & 0xFF) >= sc ||
|
||||
continue;
|
||||
}
|
||||
case JINT_SL: {
|
||||
int32_t jumpdest = i + (((int32_t)instr) >> 16);
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
|
||||
continue;
|
||||
}
|
||||
case JINT_SSS: {
|
||||
if (((int32_t)(instr >> 8) & 0xFF) >= sc ||
|
||||
((int32_t)(instr >> 16) & 0xFF) >= sc ||
|
||||
((int32_t)(instr >> 24) & 0xFF) >= sc) return 4;
|
||||
continue;
|
||||
}
|
||||
case JINT_SD:
|
||||
{
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if ((int32_t)(instr >> 16) >= def->defs_length) return 6;
|
||||
continue;
|
||||
}
|
||||
case JINT_SC:
|
||||
{
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if ((int32_t)(instr >> 16) >= def->constants_length) return 7;
|
||||
continue;
|
||||
}
|
||||
case JINT_SES:
|
||||
{
|
||||
/* How can we check the last slot index? We need info parent funcdefs. Resort
|
||||
* to runtime checks for now. Maybe invalid upvalue references could be defaulted
|
||||
* to nil? (don't commit to this in the long term, though) */
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if ((int32_t)((instr >> 16) & 0xFF) >= def->environments_length) return 8;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case JINT_SD: {
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if ((int32_t)(instr >> 16) >= def->defs_length) return 6;
|
||||
continue;
|
||||
}
|
||||
case JINT_SC: {
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if ((int32_t)(instr >> 16) >= def->constants_length) return 7;
|
||||
continue;
|
||||
}
|
||||
case JINT_SES: {
|
||||
/* How can we check the last slot index? We need info parent funcdefs. Resort
|
||||
* to runtime checks for now. Maybe invalid upvalue references could be defaulted
|
||||
* to nil? (don't commit to this in the long term, though) */
|
||||
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
|
||||
if ((int32_t)((instr >> 16) & 0xFF) >= def->environments_length) return 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,14 +498,18 @@ int32_t janet_verify(JanetFuncDef *def) {
|
||||
|
||||
/* Allocate an empty funcdef. This function may have added functionality
|
||||
* as commonalities between asm and compile arise. */
|
||||
JanetFuncDef *janet_funcdef_alloc() {
|
||||
JanetFuncDef *janet_funcdef_alloc(void) {
|
||||
JanetFuncDef *def = janet_gcalloc(JANET_MEMORY_FUNCDEF, sizeof(JanetFuncDef));
|
||||
def->environments = NULL;
|
||||
def->constants = NULL;
|
||||
def->bytecode = NULL;
|
||||
def->closure_bitset = NULL;
|
||||
def->flags = 0;
|
||||
def->slotcount = 0;
|
||||
def->symbolmap = NULL;
|
||||
def->arity = 0;
|
||||
def->min_arity = 0;
|
||||
def->max_arity = INT32_MAX;
|
||||
def->source = NULL;
|
||||
def->sourcemap = NULL;
|
||||
def->name = NULL;
|
||||
@@ -226,6 +518,7 @@ JanetFuncDef *janet_funcdef_alloc() {
|
||||
def->constants_length = 0;
|
||||
def->bytecode_length = 0;
|
||||
def->environments_length = 0;
|
||||
def->symbolmap_length = 0;
|
||||
return def;
|
||||
}
|
||||
|
||||
|
||||
379
src/core/capi.c
379
src/core/capi.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,21 +21,71 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#include "fiber.h"
|
||||
#endif
|
||||
|
||||
void janet_panicv(Janet message) {
|
||||
if (janet_vm_return_reg != NULL) {
|
||||
*janet_vm_return_reg = message;
|
||||
longjmp(*janet_vm_jmp_buf, 1);
|
||||
#ifndef JANET_SINGLE_THREADED
|
||||
#ifndef JANET_WINDOWS
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
|
||||
#ifdef JANET_TOP_LEVEL_SIGNAL
|
||||
JANET_TOP_LEVEL_SIGNAL(msg);
|
||||
#else
|
||||
fputs(msg, stdout);
|
||||
# ifdef JANET_SINGLE_THREADED
|
||||
exit(-1);
|
||||
# elif defined(JANET_WINDOWS)
|
||||
ExitThread(-1);
|
||||
# else
|
||||
pthread_exit(NULL);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void janet_signalv(JanetSignal sig, Janet message) {
|
||||
if (janet_vm.return_reg != NULL) {
|
||||
*janet_vm.return_reg = message;
|
||||
if (NULL != janet_vm.fiber) {
|
||||
janet_vm.fiber->flags |= JANET_FIBER_DID_LONGJUMP;
|
||||
}
|
||||
#if defined(JANET_BSD) || defined(JANET_APPLE)
|
||||
_longjmp(*janet_vm.signal_buf, sig);
|
||||
#else
|
||||
longjmp(*janet_vm.signal_buf, sig);
|
||||
#endif
|
||||
} else {
|
||||
fputs((const char *)janet_formatc("janet top level panic - %v\n", message), stdout);
|
||||
exit(1);
|
||||
const char *str = (const char *)janet_formatc("janet top level signal - %v\n", message);
|
||||
janet_top_level_signal(str);
|
||||
}
|
||||
}
|
||||
|
||||
void janet_panicv(Janet message) {
|
||||
janet_signalv(JANET_SIGNAL_ERROR, message);
|
||||
}
|
||||
|
||||
void janet_panicf(const char *format, ...) {
|
||||
va_list args;
|
||||
const uint8_t *ret;
|
||||
JanetBuffer buffer;
|
||||
int32_t len = 0;
|
||||
while (format[len]) len++;
|
||||
janet_buffer_init(&buffer, len);
|
||||
va_start(args, format);
|
||||
janet_formatbv(&buffer, format, args);
|
||||
va_end(args);
|
||||
ret = janet_string(buffer.data, buffer.count);
|
||||
janet_buffer_deinit(&buffer);
|
||||
janet_panics(ret);
|
||||
}
|
||||
|
||||
void janet_panic(const char *message) {
|
||||
janet_panicv(janet_cstringv(message));
|
||||
}
|
||||
@@ -73,14 +123,47 @@ type janet_get##name(const Janet *argv, int32_t n) { \
|
||||
return janet_unwrap_##name(x); \
|
||||
}
|
||||
|
||||
Janet janet_getmethod(const uint8_t *method, const JanetMethod *methods) {
|
||||
#define DEFINE_OPT(name, NAME, type) \
|
||||
type janet_opt##name(const Janet *argv, int32_t argc, int32_t n, type dflt) { \
|
||||
if (n >= argc) return dflt; \
|
||||
if (janet_checktype(argv[n], JANET_NIL)) return dflt; \
|
||||
return janet_get##name(argv, n); \
|
||||
}
|
||||
|
||||
#define DEFINE_OPTLEN(name, NAME, type) \
|
||||
type janet_opt##name(const Janet *argv, int32_t argc, int32_t n, int32_t dflt_len) { \
|
||||
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {\
|
||||
return janet_##name(dflt_len); \
|
||||
}\
|
||||
return janet_get##name(argv, n); \
|
||||
}
|
||||
|
||||
int janet_getmethod(const uint8_t *method, const JanetMethod *methods, Janet *out) {
|
||||
while (methods->name) {
|
||||
if (!janet_cstrcmp(method, methods->name))
|
||||
return janet_wrap_cfunction(methods->cfun);
|
||||
if (!janet_cstrcmp(method, methods->name)) {
|
||||
*out = janet_wrap_cfunction(methods->cfun);
|
||||
return 1;
|
||||
}
|
||||
methods++;
|
||||
}
|
||||
janet_panicf("unknown method %S invoked", method);
|
||||
return janet_wrap_nil();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Janet janet_nextmethod(const JanetMethod *methods, Janet key) {
|
||||
if (!janet_checktype(key, JANET_NIL)) {
|
||||
while (methods->name) {
|
||||
if (janet_keyeq(key, methods->name)) {
|
||||
methods++;
|
||||
break;
|
||||
}
|
||||
methods++;
|
||||
}
|
||||
}
|
||||
if (methods->name) {
|
||||
return janet_ckeywordv(methods->name);
|
||||
} else {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_GETTER(number, NUMBER, double)
|
||||
@@ -95,47 +178,177 @@ DEFINE_GETTER(buffer, BUFFER, JanetBuffer *)
|
||||
DEFINE_GETTER(fiber, FIBER, JanetFiber *)
|
||||
DEFINE_GETTER(function, FUNCTION, JanetFunction *)
|
||||
DEFINE_GETTER(cfunction, CFUNCTION, JanetCFunction)
|
||||
DEFINE_GETTER(boolean, BOOLEAN, int)
|
||||
DEFINE_GETTER(pointer, POINTER, void *)
|
||||
|
||||
int janet_getboolean(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (janet_checktype(x, JANET_TRUE)) {
|
||||
return 1;
|
||||
} else if (!janet_checktype(x, JANET_FALSE)) {
|
||||
janet_panicf("bad slot #%d, expected boolean, got %v", n, x);
|
||||
DEFINE_OPT(number, NUMBER, double)
|
||||
DEFINE_OPT(tuple, TUPLE, const Janet *)
|
||||
DEFINE_OPT(struct, STRUCT, const JanetKV *)
|
||||
DEFINE_OPT(string, STRING, const uint8_t *)
|
||||
DEFINE_OPT(keyword, KEYWORD, const uint8_t *)
|
||||
DEFINE_OPT(symbol, SYMBOL, const uint8_t *)
|
||||
DEFINE_OPT(fiber, FIBER, JanetFiber *)
|
||||
DEFINE_OPT(function, FUNCTION, JanetFunction *)
|
||||
DEFINE_OPT(cfunction, CFUNCTION, JanetCFunction)
|
||||
DEFINE_OPT(boolean, BOOLEAN, int)
|
||||
DEFINE_OPT(pointer, POINTER, void *)
|
||||
|
||||
DEFINE_OPTLEN(buffer, BUFFER, JanetBuffer *)
|
||||
DEFINE_OPTLEN(table, TABLE, JanetTable *)
|
||||
DEFINE_OPTLEN(array, ARRAY, JanetArray *)
|
||||
|
||||
const char *janet_optcstring(const Janet *argv, int32_t argc, int32_t n, const char *dflt) {
|
||||
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
|
||||
return dflt;
|
||||
}
|
||||
return 0;
|
||||
return janet_getcstring(argv, n);
|
||||
}
|
||||
|
||||
#undef DEFINE_GETTER
|
||||
#undef DEFINE_OPT
|
||||
#undef DEFINE_OPTLEN
|
||||
|
||||
const char *janet_getcstring(const Janet *argv, int32_t n) {
|
||||
if (!janet_checktype(argv[n], JANET_STRING)) {
|
||||
janet_panic_type(argv[n], n, JANET_TFLAG_STRING);
|
||||
}
|
||||
return janet_getcbytes(argv, n);
|
||||
}
|
||||
|
||||
const char *janet_getcbytes(const Janet *argv, int32_t n) {
|
||||
/* Ensure buffer 0-padded */
|
||||
if (janet_checktype(argv[n], JANET_BUFFER)) {
|
||||
JanetBuffer *b = janet_unwrap_buffer(argv[n]);
|
||||
if ((b->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC) && b->count == b->capacity) {
|
||||
/* Make a copy with janet_smalloc in the rare case we have a buffer that
|
||||
* cannot be realloced and pushing a 0 byte would panic. */
|
||||
char *new_string = janet_smalloc(b->count + 1);
|
||||
memcpy(new_string, b->data, b->count);
|
||||
new_string[b->count] = 0;
|
||||
if (strlen(new_string) != (size_t) b->count) goto badzeros;
|
||||
return new_string;
|
||||
} else {
|
||||
/* Ensure trailing 0 */
|
||||
janet_buffer_push_u8(b, 0);
|
||||
b->count--;
|
||||
if (strlen((char *)b->data) != (size_t) b->count) goto badzeros;
|
||||
return (const char *) b->data;
|
||||
}
|
||||
}
|
||||
JanetByteView view = janet_getbytes(argv, n);
|
||||
const char *cstr = (const char *)view.bytes;
|
||||
if (strlen(cstr) != (size_t) view.len) goto badzeros;
|
||||
return cstr;
|
||||
|
||||
badzeros:
|
||||
janet_panic("bytes contain embedded 0s");
|
||||
}
|
||||
|
||||
const char *janet_optcbytes(const Janet *argv, int32_t argc, int32_t n, const char *dflt) {
|
||||
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
|
||||
return dflt;
|
||||
}
|
||||
return janet_getcbytes(argv, n);
|
||||
}
|
||||
|
||||
int32_t janet_getnat(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint(x)) goto bad;
|
||||
int32_t ret = janet_unwrap_integer(x);
|
||||
if (ret < 0) goto bad;
|
||||
return ret;
|
||||
bad:
|
||||
janet_panicf("bad slot #%d, expected non-negative 32 bit signed integer, got %v", n, x);
|
||||
}
|
||||
|
||||
JanetAbstract janet_checkabstract(Janet x, const JanetAbstractType *at) {
|
||||
if (!janet_checktype(x, JANET_ABSTRACT)) return NULL;
|
||||
JanetAbstract a = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(a) != at) return NULL;
|
||||
return a;
|
||||
}
|
||||
|
||||
static int janet_strlike_cmp(JanetType type, Janet x, const char *cstring) {
|
||||
if (janet_type(x) != type) return 0;
|
||||
return !janet_cstrcmp(janet_unwrap_string(x), cstring);
|
||||
}
|
||||
|
||||
int janet_keyeq(Janet x, const char *cstring) {
|
||||
return janet_strlike_cmp(JANET_KEYWORD, x, cstring);
|
||||
}
|
||||
|
||||
int janet_streq(Janet x, const char *cstring) {
|
||||
return janet_strlike_cmp(JANET_STRING, x, cstring);
|
||||
}
|
||||
|
||||
int janet_symeq(Janet x, const char *cstring) {
|
||||
return janet_strlike_cmp(JANET_SYMBOL, x, cstring);
|
||||
}
|
||||
|
||||
int32_t janet_getinteger(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint(x)) {
|
||||
janet_panicf("bad slot #%d, expected integer, got %v", n, x);
|
||||
janet_panicf("bad slot #%d, expected 32 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return janet_unwrap_integer(x);
|
||||
}
|
||||
|
||||
uint32_t janet_getuinteger(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkuint(x)) {
|
||||
janet_panicf("bad slot #%d, expected 32 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return janet_unwrap_integer(x);
|
||||
}
|
||||
|
||||
int64_t janet_getinteger64(const Janet *argv, int32_t n) {
|
||||
#ifdef JANET_INT_TYPES
|
||||
return janet_unwrap_s64(argv[n]);
|
||||
#else
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint64(x)) {
|
||||
janet_panicf("bad slot #%d, expected 64 bit integer, got %v", n, x);
|
||||
janet_panicf("bad slot #%d, expected 64 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return (int64_t) janet_unwrap_number(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t janet_getuinteger64(const Janet *argv, int32_t n) {
|
||||
#ifdef JANET_INT_TYPES
|
||||
return janet_unwrap_u64(argv[n]);
|
||||
#else
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkuint64(x)) {
|
||||
janet_panicf("bad slot #%d, expected 64 bit unsigned integer, got %v", n, x);
|
||||
}
|
||||
return (uint64_t) janet_unwrap_number(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t janet_getsize(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checksize(x)) {
|
||||
janet_panicf("bad slot #%d, expected size, got %v", n, x);
|
||||
}
|
||||
return (size_t) janet_unwrap_number(x);
|
||||
}
|
||||
|
||||
int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which) {
|
||||
int32_t raw = janet_getinteger(argv, n);
|
||||
if (raw < 0) raw += length + 1;
|
||||
if (raw < 0 || raw > length)
|
||||
janet_panicf("%s index %d out of range [0,%d]", which, raw, length);
|
||||
return raw;
|
||||
int32_t not_raw = raw;
|
||||
if (not_raw < 0) not_raw += length + 1;
|
||||
if (not_raw < 0 || not_raw > length)
|
||||
janet_panicf("%s index %d out of range [%d,%d]", which, raw, -length - 1, length);
|
||||
return not_raw;
|
||||
}
|
||||
|
||||
int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which) {
|
||||
int32_t raw = janet_getinteger(argv, n);
|
||||
if (raw < 0) raw += length;
|
||||
if (raw < 0 || raw > length)
|
||||
janet_panicf("%s index %d out of range [0,%d)", which, raw, length);
|
||||
return raw;
|
||||
int32_t not_raw = raw;
|
||||
if (not_raw < 0) not_raw += length;
|
||||
if (not_raw < 0 || not_raw > length)
|
||||
janet_panicf("%s index %d out of range [%d,%d)", which, raw, -length, length);
|
||||
return not_raw;
|
||||
}
|
||||
|
||||
JanetView janet_getindexed(const Janet *argv, int32_t n) {
|
||||
@@ -185,13 +398,113 @@ JanetRange janet_getslice(int32_t argc, const Janet *argv) {
|
||||
range.start = 0;
|
||||
range.end = length;
|
||||
} else if (argc == 2) {
|
||||
range.start = janet_gethalfrange(argv, 1, length, "start");
|
||||
range.start = janet_checktype(argv[1], JANET_NIL)
|
||||
? 0
|
||||
: janet_gethalfrange(argv, 1, length, "start");
|
||||
range.end = length;
|
||||
} else {
|
||||
range.start = janet_gethalfrange(argv, 1, length, "start");
|
||||
range.end = janet_gethalfrange(argv, 2, length, "end");
|
||||
range.start = janet_checktype(argv[1], JANET_NIL)
|
||||
? 0
|
||||
: janet_gethalfrange(argv, 1, length, "start");
|
||||
range.end = janet_checktype(argv[2], JANET_NIL)
|
||||
? length
|
||||
: janet_gethalfrange(argv, 2, length, "end");
|
||||
if (range.end < range.start)
|
||||
range.end = range.start;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
Janet janet_dyn(const char *name) {
|
||||
if (!janet_vm.fiber) {
|
||||
if (!janet_vm.top_dyns) return janet_wrap_nil();
|
||||
return janet_table_get(janet_vm.top_dyns, janet_ckeywordv(name));
|
||||
}
|
||||
if (janet_vm.fiber->env) {
|
||||
return janet_table_get(janet_vm.fiber->env, janet_ckeywordv(name));
|
||||
} else {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
}
|
||||
|
||||
void janet_setdyn(const char *name, Janet value) {
|
||||
if (!janet_vm.fiber) {
|
||||
if (!janet_vm.top_dyns) janet_vm.top_dyns = janet_table(10);
|
||||
janet_table_put(janet_vm.top_dyns, janet_ckeywordv(name), value);
|
||||
} else {
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(1);
|
||||
}
|
||||
janet_table_put(janet_vm.fiber->env, janet_ckeywordv(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t janet_getflags(const Janet *argv, int32_t n, const char *flags) {
|
||||
uint64_t ret = 0;
|
||||
const uint8_t *keyw = janet_getkeyword(argv, n);
|
||||
int32_t klen = janet_string_length(keyw);
|
||||
int32_t flen = (int32_t) strlen(flags);
|
||||
if (flen > 64) {
|
||||
flen = 64;
|
||||
}
|
||||
for (int32_t j = 0; j < klen; j++) {
|
||||
for (int32_t i = 0; i < flen; i++) {
|
||||
if (((uint8_t) flags[i]) == keyw[j]) {
|
||||
ret |= 1ULL << i;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
janet_panicf("unexpected flag %c, expected one of \"%s\"", (char) keyw[j], flags);
|
||||
found:
|
||||
;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t janet_optnat(const Janet *argv, int32_t argc, int32_t n, int32_t dflt) {
|
||||
if (argc <= n) return dflt;
|
||||
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
|
||||
return janet_getnat(argv, n);
|
||||
}
|
||||
|
||||
int32_t janet_optinteger(const Janet *argv, int32_t argc, int32_t n, int32_t dflt) {
|
||||
if (argc <= n) return dflt;
|
||||
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
|
||||
return janet_getinteger(argv, n);
|
||||
}
|
||||
|
||||
int64_t janet_optinteger64(const Janet *argv, int32_t argc, int32_t n, int64_t dflt) {
|
||||
if (argc <= n) return dflt;
|
||||
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
|
||||
return janet_getinteger64(argv, n);
|
||||
}
|
||||
|
||||
size_t janet_optsize(const Janet *argv, int32_t argc, int32_t n, size_t dflt) {
|
||||
if (argc <= n) return dflt;
|
||||
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
|
||||
return janet_getsize(argv, n);
|
||||
}
|
||||
|
||||
void *janet_optabstract(const Janet *argv, int32_t argc, int32_t n, const JanetAbstractType *at, void *dflt) {
|
||||
if (argc <= n) return dflt;
|
||||
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
|
||||
return janet_getabstract(argv, n, at);
|
||||
}
|
||||
|
||||
/* Some definitions for function-like macros */
|
||||
|
||||
JANET_API JanetStructHead *(janet_struct_head)(const JanetKV *st) {
|
||||
return janet_struct_head(st);
|
||||
}
|
||||
|
||||
JANET_API JanetAbstractHead *(janet_abstract_head)(const void *abstract) {
|
||||
return janet_abstract_head(abstract);
|
||||
}
|
||||
|
||||
JANET_API JanetStringHead *(janet_string_head)(const uint8_t *s) {
|
||||
return janet_string_head(s);
|
||||
}
|
||||
|
||||
JANET_API JanetTupleHead *(janet_tuple_head)(const Janet *tuple) {
|
||||
return janet_tuple_head(tuple);
|
||||
}
|
||||
|
||||
260
src/core/cfuns.c
260
src/core/cfuns.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,20 +21,31 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "compile.h"
|
||||
#include "emit.h"
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
static int fixarity0(JanetFopts opts, JanetSlot *args) {
|
||||
static int arity1or2(JanetFopts opts, JanetSlot *args) {
|
||||
(void) opts;
|
||||
return janet_v_count(args) == 0;
|
||||
int32_t arity = janet_v_count(args);
|
||||
return arity == 1 || arity == 2;
|
||||
}
|
||||
static int arity2or3(JanetFopts opts, JanetSlot *args) {
|
||||
(void) opts;
|
||||
int32_t arity = janet_v_count(args);
|
||||
return arity == 2 || arity == 3;
|
||||
}
|
||||
static int fixarity1(JanetFopts opts, JanetSlot *args) {
|
||||
(void) opts;
|
||||
return janet_v_count(args) == 1;
|
||||
}
|
||||
static int maxarity1(JanetFopts opts, JanetSlot *args) {
|
||||
(void) opts;
|
||||
return janet_v_count(args) <= 1;
|
||||
}
|
||||
static int minarity2(JanetFopts opts, JanetSlot *args) {
|
||||
(void) opts;
|
||||
return janet_v_count(args) >= 2;
|
||||
@@ -62,43 +73,134 @@ static JanetSlot genericSSI(JanetFopts opts, int op, JanetSlot s, int32_t imm) {
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Emit an insruction that implements a form by itself. */
|
||||
static JanetSlot opfunction(
|
||||
JanetFopts opts,
|
||||
JanetSlot *args,
|
||||
int op,
|
||||
Janet defaultArg2) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
int32_t len;
|
||||
len = janet_v_count(args);
|
||||
JanetSlot t;
|
||||
if (len == 1) {
|
||||
t = janetc_gettarget(opts);
|
||||
janetc_emit_sss(c, op, t, args[0], janetc_cslot(defaultArg2), 1);
|
||||
return t;
|
||||
} else {
|
||||
/* len == 2 */
|
||||
t = janetc_gettarget(opts);
|
||||
janetc_emit_sss(c, op, t, args[0], args[1], 1);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Check if a value can be coerced to an immediate value */
|
||||
static int can_be_imm(Janet x, int8_t *out) {
|
||||
if (!janet_checkint(x)) return 0;
|
||||
int32_t integer = janet_unwrap_integer(x);
|
||||
if (integer > 127 || integer < -127) return 0;
|
||||
*out = (int8_t) integer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if a slot can be coerced to an immediate value */
|
||||
static int can_slot_be_imm(JanetSlot s, int8_t *out) {
|
||||
if (!(s.flags & JANET_SLOT_CONSTANT)) return 0;
|
||||
return can_be_imm(s.constant, out);
|
||||
}
|
||||
|
||||
/* Emit a series of instructions instead of a function call to a math op */
|
||||
static JanetSlot opreduce(
|
||||
JanetFopts opts,
|
||||
JanetSlot *args,
|
||||
int op,
|
||||
Janet nullary) {
|
||||
JanetFopts opts,
|
||||
JanetSlot *args,
|
||||
int op,
|
||||
int opim,
|
||||
Janet nullary,
|
||||
Janet unary) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
int32_t i, len;
|
||||
int8_t imm = 0;
|
||||
int neg = opim < 0;
|
||||
if (opim < 0) opim = -opim;
|
||||
len = janet_v_count(args);
|
||||
JanetSlot t;
|
||||
if (len == 0) {
|
||||
return janetc_cslot(nullary);
|
||||
} else if (len == 1) {
|
||||
t = janetc_gettarget(opts);
|
||||
janetc_emit_sss(c, op, t, janetc_cslot(nullary), args[0], 1);
|
||||
/* Special case subtract to be times -1 */
|
||||
if (op == JOP_SUBTRACT) {
|
||||
janetc_emit_ssi(c, JOP_MULTIPLY_IMMEDIATE, t, args[0], -1, 1);
|
||||
} else {
|
||||
janetc_emit_sss(c, op, t, janetc_cslot(unary), args[0], 1);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
t = janetc_gettarget(opts);
|
||||
janetc_emit_sss(c, op, t, args[0], args[1], 1);
|
||||
for (i = 2; i < len; i++)
|
||||
janetc_emit_sss(c, op, t, t, args[i], 1);
|
||||
if (opim && can_slot_be_imm(args[1], &imm)) {
|
||||
janetc_emit_ssi(c, opim, t, args[0], neg ? -imm : imm, 1);
|
||||
} else {
|
||||
janetc_emit_sss(c, op, t, args[0], args[1], 1);
|
||||
}
|
||||
for (i = 2; i < len; i++) {
|
||||
if (opim && can_slot_be_imm(args[i], &imm)) {
|
||||
janetc_emit_ssi(c, opim, t, t, neg ? -imm : imm, 1);
|
||||
} else {
|
||||
janetc_emit_sss(c, op, t, t, args[i], 1);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Function optimizers */
|
||||
|
||||
static JanetSlot do_propagate(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_PROPAGATE, 0, janet_wrap_nil(), janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_error(JanetFopts opts, JanetSlot *args) {
|
||||
janetc_emit_s(opts.compiler, JOP_ERROR, args[0], 0);
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_debug(JanetFopts opts, JanetSlot *args) {
|
||||
(void)args;
|
||||
janetc_emit(opts.compiler, JOP_SIGNAL | (2 << 24));
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
int32_t len = janet_v_count(args);
|
||||
JanetSlot t = janetc_gettarget(opts);
|
||||
janetc_emit_ssu(opts.compiler, JOP_SIGNAL, t,
|
||||
(len == 1) ? args[0] : janetc_cslot(janet_wrap_nil()),
|
||||
JANET_SIGNAL_DEBUG,
|
||||
1);
|
||||
return t;
|
||||
}
|
||||
static JanetSlot do_in(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_IN, 0, janet_wrap_nil(), janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_get(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_GET, janet_wrap_nil());
|
||||
if (janet_v_count(args) == 3) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
JanetSlot t = janetc_gettarget(opts);
|
||||
int target_is_default = janetc_sequal(t, args[2]);
|
||||
JanetSlot dflt_slot = args[2];
|
||||
if (target_is_default) {
|
||||
dflt_slot = janetc_farslot(c);
|
||||
janetc_copy(c, dflt_slot, t);
|
||||
}
|
||||
janetc_emit_sss(c, JOP_GET, t, args[0], args[1], 1);
|
||||
int32_t label = janetc_emit_si(c, JOP_JUMP_IF_NOT_NIL, t, 0, 0);
|
||||
janetc_copy(c, t, dflt_slot);
|
||||
if (target_is_default) janetc_freeslot(c, dflt_slot);
|
||||
int32_t current = janet_v_count(c->buffer);
|
||||
c->buffer[label] |= (current - label) << 16;
|
||||
return t;
|
||||
} else {
|
||||
return opreduce(opts, args, JOP_GET, 0, janet_wrap_nil(), janet_wrap_nil());
|
||||
}
|
||||
}
|
||||
static JanetSlot do_next(JanetFopts opts, JanetSlot *args) {
|
||||
return opfunction(opts, args, JOP_NEXT, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_cmp(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_COMPARE, 0, janet_wrap_nil(), janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_put(JanetFopts opts, JanetSlot *args) {
|
||||
if (opts.flags & JANET_FOPTS_DROP) {
|
||||
@@ -115,19 +217,26 @@ static JanetSlot do_length(JanetFopts opts, JanetSlot *args) {
|
||||
return genericSS(opts, JOP_LENGTH, args[0]);
|
||||
}
|
||||
static JanetSlot do_yield(JanetFopts opts, JanetSlot *args) {
|
||||
return genericSSI(opts, JOP_SIGNAL, args[0], 3);
|
||||
if (janet_v_count(args) == 0) {
|
||||
return genericSSI(opts, JOP_SIGNAL, janetc_cslot(janet_wrap_nil()), 3);
|
||||
} else {
|
||||
return genericSSI(opts, JOP_SIGNAL, args[0], 3);
|
||||
}
|
||||
}
|
||||
static JanetSlot do_resume(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_RESUME, janet_wrap_nil());
|
||||
return opfunction(opts, args, JOP_RESUME, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_cancel(JanetFopts opts, JanetSlot *args) {
|
||||
return opfunction(opts, args, JOP_CANCEL, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) {
|
||||
/* Push phase */
|
||||
JanetCompiler *c = opts.compiler;
|
||||
int32_t i;
|
||||
for (i = 1; i < janet_v_count(args) - 3; i += 3)
|
||||
janetc_emit_sss(c, JOP_PUSH_3, args[i], args[i+1], args[i+2], 0);
|
||||
janetc_emit_sss(c, JOP_PUSH_3, args[i], args[i + 1], args[i + 2], 0);
|
||||
if (i == janet_v_count(args) - 3)
|
||||
janetc_emit_ss(c, JOP_PUSH_2, args[i], args[i+1], 0);
|
||||
janetc_emit_ss(c, JOP_PUSH_2, args[i], args[i + 1], 0);
|
||||
else if (i == janet_v_count(args) - 2)
|
||||
janetc_emit_s(c, JOP_PUSH, args[i], 0);
|
||||
/* Push array phase */
|
||||
@@ -148,34 +257,43 @@ static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) {
|
||||
/* Variadic operators specialization */
|
||||
|
||||
static JanetSlot do_add(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_ADD, janet_wrap_integer(0));
|
||||
return opreduce(opts, args, JOP_ADD, JOP_ADD_IMMEDIATE, janet_wrap_integer(0), janet_wrap_integer(0));
|
||||
}
|
||||
static JanetSlot do_sub(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_SUBTRACT, janet_wrap_integer(0));
|
||||
return opreduce(opts, args, JOP_SUBTRACT, JOP_SUBTRACT_IMMEDIATE, janet_wrap_integer(0), janet_wrap_integer(0));
|
||||
}
|
||||
static JanetSlot do_mul(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_MULTIPLY, janet_wrap_integer(1));
|
||||
return opreduce(opts, args, JOP_MULTIPLY, JOP_MULTIPLY_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_div(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_DIVIDE, janet_wrap_integer(1));
|
||||
return opreduce(opts, args, JOP_DIVIDE, JOP_DIVIDE_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_divf(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_DIVIDE_FLOOR, 0, janet_wrap_integer(1), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_modulo(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_MODULO, 0, janet_wrap_integer(0), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_remainder(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_REMAINDER, 0, janet_wrap_integer(0), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_band(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_BAND, janet_wrap_integer(-1));
|
||||
return opreduce(opts, args, JOP_BAND, 0, janet_wrap_integer(-1), janet_wrap_integer(-1));
|
||||
}
|
||||
static JanetSlot do_bor(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_BOR, janet_wrap_integer(0));
|
||||
return opreduce(opts, args, JOP_BOR, 0, janet_wrap_integer(0), janet_wrap_integer(0));
|
||||
}
|
||||
static JanetSlot do_bxor(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_BXOR, janet_wrap_integer(0));
|
||||
return opreduce(opts, args, JOP_BXOR, 0, janet_wrap_integer(0), janet_wrap_integer(0));
|
||||
}
|
||||
static JanetSlot do_lshift(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_SHIFT_LEFT, janet_wrap_integer(1));
|
||||
return opreduce(opts, args, JOP_SHIFT_LEFT, JOP_SHIFT_LEFT_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_rshift(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_SHIFT_RIGHT, janet_wrap_integer(1));
|
||||
return opreduce(opts, args, JOP_SHIFT_RIGHT, JOP_SHIFT_RIGHT_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_rshiftu(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_SHIFT_RIGHT, janet_wrap_integer(1));
|
||||
return opreduce(opts, args, JOP_SHIFT_RIGHT_UNSIGNED, JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
|
||||
}
|
||||
static JanetSlot do_bnot(JanetFopts opts, JanetSlot *args) {
|
||||
return genericSS(opts, JOP_BNOT, args[0]);
|
||||
@@ -183,35 +301,35 @@ static JanetSlot do_bnot(JanetFopts opts, JanetSlot *args) {
|
||||
|
||||
/* Specialization for comparators */
|
||||
static JanetSlot compreduce(
|
||||
JanetFopts opts,
|
||||
JanetSlot *args,
|
||||
int op,
|
||||
int invert) {
|
||||
JanetFopts opts,
|
||||
JanetSlot *args,
|
||||
int op,
|
||||
int opim,
|
||||
int invert) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
int32_t i, len;
|
||||
int8_t imm = 0;
|
||||
len = janet_v_count(args);
|
||||
int32_t *labels = NULL;
|
||||
JanetSlot t;
|
||||
if (len < 2) {
|
||||
return invert
|
||||
? janetc_cslot(janet_wrap_false())
|
||||
: janetc_cslot(janet_wrap_true());
|
||||
? janetc_cslot(janet_wrap_false())
|
||||
: janetc_cslot(janet_wrap_true());
|
||||
}
|
||||
t = janetc_gettarget(opts);
|
||||
for (i = 1; i < len; i++) {
|
||||
janetc_emit_sss(c, op, t, args[i - 1], args[i], 1);
|
||||
if (opim && can_slot_be_imm(args[i], &imm)) {
|
||||
janetc_emit_ssi(c, opim, t, args[i - 1], imm, 1);
|
||||
} else {
|
||||
janetc_emit_sss(c, op, t, args[i - 1], args[i], 1);
|
||||
}
|
||||
if (i != (len - 1)) {
|
||||
int32_t label = janetc_emit_si(c, JOP_JUMP_IF_NOT, t, 0, 1);
|
||||
int32_t label = janetc_emit_si(c, invert ? JOP_JUMP_IF : JOP_JUMP_IF_NOT, t, 0, 1);
|
||||
janet_v_push(labels, label);
|
||||
}
|
||||
}
|
||||
int32_t end = janet_v_count(c->buffer);
|
||||
if (invert) {
|
||||
janetc_emit_si(c, JOP_JUMP_IF, t, 3, 0);
|
||||
janetc_emit_s(c, JOP_LOAD_TRUE, t, 1);
|
||||
janetc_emit(c, JOP_JUMP | (2 << 8));
|
||||
janetc_emit_s(c, JOP_LOAD_FALSE, t, 1);
|
||||
}
|
||||
for (i = 0; i < janet_v_count(labels); i++) {
|
||||
int32_t label = labels[i];
|
||||
c->buffer[label] |= ((end - label) << 16);
|
||||
@@ -220,51 +338,33 @@ static JanetSlot compreduce(
|
||||
return t;
|
||||
}
|
||||
|
||||
static JanetSlot do_order_gt(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_GREATER_THAN, 0);
|
||||
}
|
||||
static JanetSlot do_order_lt(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_LESS_THAN, 0);
|
||||
}
|
||||
static JanetSlot do_order_gte(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_LESS_THAN, 1);
|
||||
}
|
||||
static JanetSlot do_order_lte(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_GREATER_THAN, 1);
|
||||
}
|
||||
static JanetSlot do_order_eq(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_EQUALS, 0);
|
||||
}
|
||||
static JanetSlot do_order_neq(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_EQUALS, 1);
|
||||
}
|
||||
static JanetSlot do_gt(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_NUMERIC_GREATER_THAN, 0);
|
||||
return compreduce(opts, args, JOP_GREATER_THAN, JOP_GREATER_THAN_IMMEDIATE, 0);
|
||||
}
|
||||
static JanetSlot do_lt(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_NUMERIC_LESS_THAN, 0);
|
||||
return compreduce(opts, args, JOP_LESS_THAN, JOP_LESS_THAN_IMMEDIATE, 0);
|
||||
}
|
||||
static JanetSlot do_gte(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_NUMERIC_GREATER_THAN_EQUAL, 0);
|
||||
return compreduce(opts, args, JOP_GREATER_THAN_EQUAL, 0, 0);
|
||||
}
|
||||
static JanetSlot do_lte(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_NUMERIC_LESS_THAN_EQUAL, 0);
|
||||
return compreduce(opts, args, JOP_LESS_THAN_EQUAL, 0, 0);
|
||||
}
|
||||
static JanetSlot do_eq(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_NUMERIC_EQUAL, 0);
|
||||
return compreduce(opts, args, JOP_EQUALS, JOP_EQUALS_IMMEDIATE, 0);
|
||||
}
|
||||
static JanetSlot do_neq(JanetFopts opts, JanetSlot *args) {
|
||||
return compreduce(opts, args, JOP_NUMERIC_EQUAL, 1);
|
||||
return compreduce(opts, args, JOP_NOT_EQUALS, JOP_NOT_EQUALS_IMMEDIATE, 1);
|
||||
}
|
||||
|
||||
/* Arranged by tag */
|
||||
static const JanetFunOptimizer optimizers[] = {
|
||||
{fixarity0, do_debug},
|
||||
{maxarity1, do_debug},
|
||||
{fixarity1, do_error},
|
||||
{minarity2, do_apply},
|
||||
{fixarity1, do_yield},
|
||||
{fixarity2, do_resume},
|
||||
{fixarity2, do_get},
|
||||
{maxarity1, do_yield},
|
||||
{arity1or2, do_resume},
|
||||
{fixarity2, do_in},
|
||||
{fixarity3, do_put},
|
||||
{fixarity1, do_length},
|
||||
{NULL, do_add},
|
||||
@@ -278,18 +378,20 @@ static const JanetFunOptimizer optimizers[] = {
|
||||
{NULL, do_rshift},
|
||||
{NULL, do_rshiftu},
|
||||
{fixarity1, do_bnot},
|
||||
{NULL, do_order_gt},
|
||||
{NULL, do_order_lt},
|
||||
{NULL, do_order_gte},
|
||||
{NULL, do_order_lte},
|
||||
{NULL, do_order_eq},
|
||||
{NULL, do_order_neq},
|
||||
{NULL, do_gt},
|
||||
{NULL, do_lt},
|
||||
{NULL, do_gte},
|
||||
{NULL, do_lte},
|
||||
{NULL, do_eq},
|
||||
{NULL, do_neq}
|
||||
{NULL, do_neq},
|
||||
{fixarity2, do_propagate},
|
||||
{arity2or3, do_get},
|
||||
{arity1or2, do_next},
|
||||
{NULL, do_modulo},
|
||||
{NULL, do_remainder},
|
||||
{fixarity2, do_cmp},
|
||||
{fixarity2, do_cancel},
|
||||
{NULL, do_divf}
|
||||
};
|
||||
|
||||
const JanetFunOptimizer *janetc_funopt(uint32_t flags) {
|
||||
@@ -297,7 +399,7 @@ const JanetFunOptimizer *janetc_funopt(uint32_t flags) {
|
||||
if (tag == 0)
|
||||
return NULL;
|
||||
uint32_t index = tag - 1;
|
||||
if (index >= (sizeof(optimizers)/sizeof(optimizers[0])))
|
||||
if (index >= (sizeof(optimizers) / sizeof(optimizers[0])))
|
||||
return NULL;
|
||||
return optimizers + index;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,11 +21,13 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "compile.h"
|
||||
#include "emit.h"
|
||||
#include "vector.h"
|
||||
#include "util.h"
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
JanetFopts janetc_fopts_default(JanetCompiler *c) {
|
||||
@@ -51,6 +53,36 @@ void janetc_cerror(JanetCompiler *c, const char *m) {
|
||||
janetc_error(c, janet_cstring(m));
|
||||
}
|
||||
|
||||
static const char *janet_lint_level_names[] = {
|
||||
"relaxed",
|
||||
"normal",
|
||||
"strict"
|
||||
};
|
||||
|
||||
/* Emit compiler linter messages */
|
||||
void janetc_lintf(JanetCompiler *c, JanetCompileLintLevel level, const char *format, ...) {
|
||||
if (NULL != c->lints) {
|
||||
/* format message */
|
||||
va_list args;
|
||||
JanetBuffer buffer;
|
||||
int32_t len = 0;
|
||||
while (format[len]) len++;
|
||||
janet_buffer_init(&buffer, len);
|
||||
va_start(args, format);
|
||||
janet_formatbv(&buffer, format, args);
|
||||
va_end(args);
|
||||
const uint8_t *str = janet_string(buffer.data, buffer.count);
|
||||
janet_buffer_deinit(&buffer);
|
||||
/* construct linting payload */
|
||||
Janet *payload = janet_tuple_begin(4);
|
||||
payload[0] = janet_ckeywordv(janet_lint_level_names[level]);
|
||||
payload[1] = c->current_mapping.line == -1 ? janet_wrap_nil() : janet_wrap_integer(c->current_mapping.line);
|
||||
payload[2] = c->current_mapping.column == -1 ? janet_wrap_nil() : janet_wrap_integer(c->current_mapping.column);
|
||||
payload[3] = janet_wrap_string(str);
|
||||
janet_array_push(c->lints, janet_wrap_tuple(janet_tuple_end(payload)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Free a slot */
|
||||
void janetc_freeslot(JanetCompiler *c, JanetSlot s) {
|
||||
if (s.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF | JANET_SLOT_NAMED)) return;
|
||||
@@ -61,10 +93,14 @@ void janetc_freeslot(JanetCompiler *c, JanetSlot s) {
|
||||
/* Add a slot to a scope with a symbol associated with it (def or var). */
|
||||
void janetc_nameslot(JanetCompiler *c, const uint8_t *sym, JanetSlot s) {
|
||||
SymPair sp;
|
||||
int32_t cnt = janet_v_count(c->buffer);
|
||||
sp.sym = sym;
|
||||
sp.sym2 = sym;
|
||||
sp.slot = s;
|
||||
sp.keep = 0;
|
||||
sp.slot.flags |= JANET_SLOT_NAMED;
|
||||
sp.birth_pc = cnt ? cnt - 1 : 0;
|
||||
sp.death_pc = UINT32_MAX;
|
||||
janet_v_push(c->scope->syms, sp);
|
||||
}
|
||||
|
||||
@@ -97,10 +133,10 @@ void janetc_scope(JanetScope *s, JanetCompiler *c, int flags, const char *name)
|
||||
scope.syms = NULL;
|
||||
scope.envs = NULL;
|
||||
scope.defs = NULL;
|
||||
scope.selfconst = -1;
|
||||
scope.bytecode_start = janet_v_count(c->buffer);
|
||||
scope.flags = flags;
|
||||
scope.parent = c->scope;
|
||||
janetc_regalloc_init(&scope.ua);
|
||||
/* Inherit slots */
|
||||
if ((!(flags & JANET_SCOPE_FUNCTION)) && c->scope) {
|
||||
janetc_regalloc_clone(&scope.ra, &(c->scope->ra));
|
||||
@@ -127,27 +163,34 @@ void janetc_popscope(JanetCompiler *c) {
|
||||
if (oldscope->flags & JANET_SCOPE_CLOSURE) {
|
||||
newscope->flags |= JANET_SCOPE_CLOSURE;
|
||||
}
|
||||
if (newscope->ra.max < oldscope->ra.max)
|
||||
if (newscope->ra.max < oldscope->ra.max) {
|
||||
newscope->ra.max = oldscope->ra.max;
|
||||
|
||||
/* Keep upvalue slots */
|
||||
for (int32_t i = 0; i < janet_v_count(oldscope->syms); i++) {
|
||||
SymPair pair = oldscope->syms[i];
|
||||
if (pair.keep) {
|
||||
/* The variable should not be lexically accessible */
|
||||
pair.sym = NULL;
|
||||
janet_v_push(newscope->syms, pair);
|
||||
janetc_regalloc_touch(&newscope->ra, pair.slot.index);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep upvalue slots and symbols for debugging. */
|
||||
for (int32_t i = 0; i < janet_v_count(oldscope->syms); i++) {
|
||||
SymPair pair = oldscope->syms[i];
|
||||
/* The variable should not be lexically accessible */
|
||||
pair.sym = NULL;
|
||||
if (pair.death_pc == UINT32_MAX) {
|
||||
pair.death_pc = (uint32_t) janet_v_count(c->buffer);
|
||||
}
|
||||
if (pair.keep) {
|
||||
/* The variable should also not be included in the locals */
|
||||
pair.sym2 = NULL;
|
||||
janetc_regalloc_touch(&newscope->ra, pair.slot.index);
|
||||
}
|
||||
janet_v_push(newscope->syms, pair);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the old scope */
|
||||
janet_v_free(oldscope->consts);
|
||||
janet_v_free(oldscope->syms);
|
||||
janet_v_free(oldscope->envs);
|
||||
janet_v_free(oldscope->defs);
|
||||
janetc_regalloc_deinit(&oldscope->ra);
|
||||
janetc_regalloc_deinit(&oldscope->ua);
|
||||
/* Update pointer */
|
||||
if (newscope)
|
||||
newscope->child = NULL;
|
||||
@@ -164,10 +207,43 @@ void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot) {
|
||||
}
|
||||
}
|
||||
|
||||
static int lookup_missing(
|
||||
JanetCompiler *c,
|
||||
const uint8_t *sym,
|
||||
JanetFunction *handler,
|
||||
JanetBinding *out) {
|
||||
int32_t minar = handler->def->min_arity;
|
||||
int32_t maxar = handler->def->max_arity;
|
||||
if (minar > 1 || maxar < 1) {
|
||||
janetc_error(c, janet_cstring("missing symbol lookup handler must take 1 argument"));
|
||||
return 0;
|
||||
}
|
||||
Janet args[1] = { janet_wrap_symbol(sym) };
|
||||
JanetFiber *fiberp = janet_fiber(handler, 64, 1, args);
|
||||
if (NULL == fiberp) {
|
||||
janetc_error(c, janet_cstring("failed to call missing symbol lookup handler"));
|
||||
return 0;
|
||||
}
|
||||
fiberp->env = c->env;
|
||||
int lock = janet_gclock();
|
||||
Janet tempOut;
|
||||
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
|
||||
janet_gcunlock(lock);
|
||||
if (status != JANET_SIGNAL_OK) {
|
||||
janetc_error(c, janet_formatc("(lookup) %V", tempOut));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert return value as entry. */
|
||||
/* Alternative could use janet_resolve_ext(c->env, sym) to read result from environment. */
|
||||
*out = janet_binding_from_entry(tempOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allow searching for symbols. Return information about the symbol */
|
||||
JanetSlot janetc_resolve(
|
||||
JanetCompiler *c,
|
||||
const uint8_t *sym) {
|
||||
JanetCompiler *c,
|
||||
const uint8_t *sym) {
|
||||
|
||||
JanetSlot ret = janetc_cslot(janet_wrap_nil());
|
||||
JanetScope *scope = c->scope;
|
||||
@@ -196,29 +272,66 @@ JanetSlot janetc_resolve(
|
||||
|
||||
/* Symbol not found - check for global */
|
||||
{
|
||||
Janet check;
|
||||
JanetBindingType btype = janet_resolve(c->env, sym, &check);
|
||||
switch (btype) {
|
||||
JanetBinding binding = janet_resolve_ext(c->env, sym);
|
||||
if (binding.type == JANET_BINDING_NONE) {
|
||||
Janet handler = janet_table_get(c->env, janet_ckeywordv("missing-symbol"));
|
||||
switch (janet_type(handler)) {
|
||||
case JANET_NIL:
|
||||
break;
|
||||
case JANET_FUNCTION:
|
||||
if (!lookup_missing(c, sym, janet_unwrap_function(handler), &binding))
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
break;
|
||||
default:
|
||||
janetc_error(c, janet_formatc("invalid lookup handler %V", handler));
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
}
|
||||
}
|
||||
|
||||
switch (binding.type) {
|
||||
default:
|
||||
case JANET_BINDING_NONE:
|
||||
janetc_error(c, janet_formatc("unknown symbol %q", sym));
|
||||
janetc_error(c, janet_formatc("unknown symbol %q", janet_wrap_symbol(sym)));
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
case JANET_BINDING_DEF:
|
||||
case JANET_BINDING_MACRO: /* Macro should function like defs when not in calling pos */
|
||||
return janetc_cslot(check);
|
||||
case JANET_BINDING_VAR:
|
||||
{
|
||||
JanetSlot ret = janetc_cslot(check);
|
||||
/* TODO save type info */
|
||||
ret = janetc_cslot(binding.value);
|
||||
break;
|
||||
case JANET_BINDING_DYNAMIC_DEF:
|
||||
case JANET_BINDING_DYNAMIC_MACRO:
|
||||
ret = janetc_cslot(binding.value);
|
||||
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOTTYPE_ANY;
|
||||
ret.flags &= ~JANET_SLOT_CONSTANT;
|
||||
break;
|
||||
case JANET_BINDING_VAR: {
|
||||
ret = janetc_cslot(binding.value);
|
||||
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY;
|
||||
ret.flags &= ~JANET_SLOT_CONSTANT;
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
JanetCompileLintLevel depLevel = JANET_C_LINT_RELAXED;
|
||||
switch (binding.deprecation) {
|
||||
case JANET_BINDING_DEP_NONE:
|
||||
break;
|
||||
case JANET_BINDING_DEP_RELAXED:
|
||||
depLevel = JANET_C_LINT_RELAXED;
|
||||
break;
|
||||
case JANET_BINDING_DEP_NORMAL:
|
||||
depLevel = JANET_C_LINT_NORMAL;
|
||||
break;
|
||||
case JANET_BINDING_DEP_STRICT:
|
||||
depLevel = JANET_C_LINT_STRICT;
|
||||
break;
|
||||
}
|
||||
if (binding.deprecation != JANET_BINDING_DEP_NONE) {
|
||||
janetc_lintf(c, depLevel, "%q is deprecated", janet_wrap_symbol(sym));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Symbol was found */
|
||||
found:
|
||||
found:
|
||||
|
||||
/* Constants can be returned immediately (they are stateless) */
|
||||
if (ret.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF))
|
||||
@@ -231,11 +344,17 @@ JanetSlot janetc_resolve(
|
||||
}
|
||||
|
||||
/* non-local scope needs to expose its environment */
|
||||
JanetScope *original_scope = scope;
|
||||
pair->keep = 1;
|
||||
while (scope && !(scope->flags & JANET_SCOPE_FUNCTION))
|
||||
scope = scope->parent;
|
||||
janet_assert(scope, "invalid scopes");
|
||||
scope->flags |= JANET_SCOPE_ENV;
|
||||
|
||||
/* In the function scope, allocate the slot as an upvalue */
|
||||
janetc_regalloc_touch(&scope->ua, ret.index);
|
||||
|
||||
/* Iterate through child scopes and make sure environment is propagated */
|
||||
scope = scope->child;
|
||||
|
||||
/* Propagate env up to current scope */
|
||||
@@ -247,7 +366,7 @@ JanetSlot janetc_resolve(
|
||||
/* Check if scope already has env. If so, break */
|
||||
len = janet_v_count(scope->envs);
|
||||
for (j = 0; j < len; j++) {
|
||||
if (scope->envs[j] == envindex) {
|
||||
if (scope->envs[j].envindex == envindex) {
|
||||
scopefound = 1;
|
||||
envindex = j;
|
||||
break;
|
||||
@@ -256,7 +375,10 @@ JanetSlot janetc_resolve(
|
||||
/* Add the environment if it is not already referenced */
|
||||
if (!scopefound) {
|
||||
len = janet_v_count(scope->envs);
|
||||
janet_v_push(scope->envs, envindex);
|
||||
JanetEnvRef ref;
|
||||
ref.envindex = envindex;
|
||||
ref.scope = original_scope;
|
||||
janet_v_push(scope->envs, ref);
|
||||
envindex = len;
|
||||
}
|
||||
}
|
||||
@@ -283,8 +405,8 @@ JanetSlot janetc_return(JanetCompiler *c, JanetSlot s) {
|
||||
JanetSlot janetc_gettarget(JanetFopts opts) {
|
||||
JanetSlot slot;
|
||||
if ((opts.flags & JANET_FOPTS_HINT) &&
|
||||
(opts.hint.envindex < 0) &&
|
||||
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
|
||||
(opts.hint.envindex < 0) &&
|
||||
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
|
||||
slot = opts.hint;
|
||||
} else {
|
||||
slot.envindex = -1;
|
||||
@@ -300,6 +422,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
|
||||
int32_t i;
|
||||
JanetSlot *ret = NULL;
|
||||
JanetFopts subopts = janetc_fopts_default(c);
|
||||
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
|
||||
for (i = 0; i < len; i++) {
|
||||
janet_v_push(ret, janetc_value(subopts, vals[i]));
|
||||
}
|
||||
@@ -310,10 +433,11 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
|
||||
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
|
||||
JanetSlot *ret = NULL;
|
||||
JanetFopts subopts = janetc_fopts_default(c);
|
||||
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
|
||||
const JanetKV *kvs = NULL;
|
||||
int32_t cap, i, len;
|
||||
int32_t cap = 0, len = 0;
|
||||
janet_dictionary_view(ds, &kvs, &len, &cap);
|
||||
for (i = 0; i < cap; i++) {
|
||||
for (int32_t i = 0; i < cap; i++) {
|
||||
if (janet_checktype(kvs[i].key, JANET_NIL)) continue;
|
||||
janet_v_push(ret, janetc_value(subopts, kvs[i].key));
|
||||
janet_v_push(ret, janetc_value(subopts, kvs[i].value));
|
||||
@@ -321,33 +445,46 @@ JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Push slots load via janetc_toslots. */
|
||||
void janetc_pushslots(JanetCompiler *c, JanetSlot *slots) {
|
||||
/* Push slots loaded via janetc_toslots. Return the minimum number of slots pushed,
|
||||
* or -1 - min_arity if there is a splice. (if there is no splice, min_arity is also
|
||||
* the maximum possible arity). */
|
||||
int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots) {
|
||||
int32_t i;
|
||||
int32_t count = janet_v_count(slots);
|
||||
int32_t min_arity = 0;
|
||||
int has_splice = 0;
|
||||
for (i = 0; i < count;) {
|
||||
if (slots[i].flags & JANET_SLOT_SPLICED) {
|
||||
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i], 0);
|
||||
i++;
|
||||
has_splice = 1;
|
||||
} else if (i + 1 == count) {
|
||||
janetc_emit_s(c, JOP_PUSH, slots[i], 0);
|
||||
i++;
|
||||
min_arity++;
|
||||
} else if (slots[i + 1].flags & JANET_SLOT_SPLICED) {
|
||||
janetc_emit_s(c, JOP_PUSH, slots[i], 0);
|
||||
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i+1], 0);
|
||||
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i + 1], 0);
|
||||
i += 2;
|
||||
min_arity++;
|
||||
has_splice = 1;
|
||||
} else if (i + 2 == count) {
|
||||
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i+1], 0);
|
||||
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i + 1], 0);
|
||||
i += 2;
|
||||
min_arity += 2;
|
||||
} else if (slots[i + 2].flags & JANET_SLOT_SPLICED) {
|
||||
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i+1], 0);
|
||||
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i+2], 0);
|
||||
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i + 1], 0);
|
||||
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i + 2], 0);
|
||||
i += 3;
|
||||
min_arity += 2;
|
||||
has_splice = 1;
|
||||
} else {
|
||||
janetc_emit_sss(c, JOP_PUSH_3, slots[i], slots[i+1], slots[i+2], 0);
|
||||
janetc_emit_sss(c, JOP_PUSH_3, slots[i], slots[i + 1], slots[i + 2], 0);
|
||||
i += 3;
|
||||
min_arity += 3;
|
||||
}
|
||||
}
|
||||
return has_splice ? (-1 - min_arity) : min_arity;
|
||||
}
|
||||
|
||||
/* Check if a list of slots has any spliced slots */
|
||||
@@ -379,6 +516,7 @@ void janetc_throwaway(JanetFopts opts, Janet x) {
|
||||
int32_t mapbufstart = janet_v_count(c->mapbuffer);
|
||||
janetc_scope(&unusedScope, c, JANET_SCOPE_UNUSED, "unusued");
|
||||
janetc_value(opts, x);
|
||||
janetc_lintf(c, JANET_C_LINT_STRICT, "dead code, consider removing %.2q", x);
|
||||
janetc_popscope(c);
|
||||
if (c->buffer) {
|
||||
janet_v__cnt(c->buffer) = bufstart;
|
||||
@@ -404,7 +542,68 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
|
||||
/* TODO janet function inlining (no c functions)*/
|
||||
}
|
||||
if (!specialized) {
|
||||
janetc_pushslots(c, slots);
|
||||
int32_t min_arity = janetc_pushslots(c, slots);
|
||||
/* Check for provably incorrect function calls */
|
||||
if (fun.flags & JANET_SLOT_CONSTANT) {
|
||||
|
||||
/* Check for bad arity type if fun is a constant */
|
||||
switch (janet_type(fun.constant)) {
|
||||
case JANET_FUNCTION: {
|
||||
JanetFunction *f = janet_unwrap_function(fun.constant);
|
||||
int32_t min = f->def->min_arity;
|
||||
int32_t max = f->def->max_arity;
|
||||
if (min_arity < 0) {
|
||||
/* Call has splices */
|
||||
min_arity = -1 - min_arity;
|
||||
if (min_arity > max && max >= 0) {
|
||||
const uint8_t *es = janet_formatc(
|
||||
"%v expects at most %d argument%s, got at least %d",
|
||||
fun.constant, max, max == 1 ? "" : "s", min_arity);
|
||||
janetc_error(c, es);
|
||||
}
|
||||
} else {
|
||||
/* Call has no splices */
|
||||
if (min_arity > max && max >= 0) {
|
||||
const uint8_t *es = janet_formatc(
|
||||
"%v expects at most %d argument%s, got %d",
|
||||
fun.constant, max, max == 1 ? "" : "s", min_arity);
|
||||
janetc_error(c, es);
|
||||
}
|
||||
if (min_arity < min) {
|
||||
const uint8_t *es = janet_formatc(
|
||||
"%v expects at least %d argument%s, got %d",
|
||||
fun.constant, min, min == 1 ? "" : "s", min_arity);
|
||||
janetc_error(c, es);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JANET_CFUNCTION:
|
||||
case JANET_ABSTRACT:
|
||||
case JANET_NIL:
|
||||
break;
|
||||
case JANET_KEYWORD:
|
||||
if (min_arity == 0) {
|
||||
const uint8_t *es = janet_formatc("%v expects at least 1 argument, got 0",
|
||||
fun.constant);
|
||||
janetc_error(c, es);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (min_arity > 1 || min_arity == 0) {
|
||||
const uint8_t *es = janet_formatc("%v expects 1 argument, got %d",
|
||||
fun.constant, min_arity);
|
||||
janetc_error(c, es);
|
||||
}
|
||||
if (min_arity < -2) {
|
||||
const uint8_t *es = janet_formatc("%v expects 1 argument, got at least %d",
|
||||
fun.constant, -1 - min_arity);
|
||||
janetc_error(c, es);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((opts.flags & JANET_FOPTS_TAIL) &&
|
||||
/* Prevent top level tail calls for better errors */
|
||||
!(c->scope->flags & JANET_SCOPE_TOP)) {
|
||||
@@ -423,10 +622,40 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
|
||||
static JanetSlot janetc_maker(JanetFopts opts, JanetSlot *slots, int op) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
JanetSlot retslot;
|
||||
janetc_pushslots(c, slots);
|
||||
janetc_freeslots(c, slots);
|
||||
retslot = janetc_gettarget(opts);
|
||||
janetc_emit_s(c, op, retslot, 1);
|
||||
|
||||
/* Check if this structure is composed entirely of constants */
|
||||
int can_inline = 1;
|
||||
for (int32_t i = 0; i < janet_v_count(slots); i++) {
|
||||
if (!(slots[i].flags & JANET_SLOT_CONSTANT) ||
|
||||
(slots[i].flags & JANET_SLOT_SPLICED)) {
|
||||
can_inline = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_inline && (op == JOP_MAKE_STRUCT)) {
|
||||
JanetKV *st = janet_struct_begin(janet_v_count(slots) / 2);
|
||||
for (int32_t i = 0; i < janet_v_count(slots); i += 2) {
|
||||
Janet k = slots[i].constant;
|
||||
Janet v = slots[i + 1].constant;
|
||||
janet_struct_put(st, k, v);
|
||||
}
|
||||
retslot = janetc_cslot(janet_wrap_struct(janet_struct_end(st)));
|
||||
janetc_freeslots(c, slots);
|
||||
} else if (can_inline && (op == JOP_MAKE_TUPLE)) {
|
||||
Janet *tup = janet_tuple_begin(janet_v_count(slots));
|
||||
for (int32_t i = 0; i < janet_v_count(slots); i++) {
|
||||
tup[i] = slots[i].constant;
|
||||
}
|
||||
retslot = janetc_cslot(janet_wrap_tuple(janet_tuple_end(tup)));
|
||||
janetc_freeslots(c, slots);
|
||||
} else {
|
||||
janetc_pushslots(c, slots);
|
||||
janetc_freeslots(c, slots);
|
||||
retslot = janetc_gettarget(opts);
|
||||
janetc_emit_s(c, op, retslot, 1);
|
||||
}
|
||||
|
||||
return retslot;
|
||||
}
|
||||
|
||||
@@ -434,15 +663,23 @@ static JanetSlot janetc_array(JanetFopts opts, Janet x) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
JanetArray *a = janet_unwrap_array(x);
|
||||
return janetc_maker(opts,
|
||||
janetc_toslots(c, a->data, a->count),
|
||||
JOP_MAKE_ARRAY);
|
||||
janetc_toslots(c, a->data, a->count),
|
||||
JOP_MAKE_ARRAY);
|
||||
}
|
||||
|
||||
static JanetSlot janetc_tuple(JanetFopts opts, Janet x) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
const Janet *t = janet_unwrap_tuple(x);
|
||||
return janetc_maker(opts,
|
||||
janetc_toslots(c, t, janet_tuple_length(t)),
|
||||
JOP_MAKE_TUPLE);
|
||||
}
|
||||
|
||||
static JanetSlot janetc_tablector(JanetFopts opts, Janet x, int op) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
return janetc_maker(opts,
|
||||
janetc_toslotskv(c, x),
|
||||
op);
|
||||
janetc_toslotskv(c, x),
|
||||
op);
|
||||
}
|
||||
|
||||
static JanetSlot janetc_bufferctor(JanetFopts opts, Janet x) {
|
||||
@@ -450,27 +687,30 @@ static JanetSlot janetc_bufferctor(JanetFopts opts, Janet x) {
|
||||
JanetBuffer *b = janet_unwrap_buffer(x);
|
||||
Janet onearg = janet_stringv(b->data, b->count);
|
||||
return janetc_maker(opts,
|
||||
janetc_toslots(c, &onearg, 1),
|
||||
JOP_MAKE_BUFFER);
|
||||
janetc_toslots(c, &onearg, 1),
|
||||
JOP_MAKE_BUFFER);
|
||||
}
|
||||
|
||||
/* Expand a macro one time. Also get the special form compiler if we
|
||||
* find that instead. */
|
||||
static int macroexpand1(
|
||||
JanetCompiler *c,
|
||||
Janet x,
|
||||
Janet *out,
|
||||
const JanetSpecial **spec) {
|
||||
JanetCompiler *c,
|
||||
Janet x,
|
||||
Janet *out,
|
||||
const JanetSpecial **spec) {
|
||||
if (!janet_checktype(x, JANET_TUPLE))
|
||||
return 0;
|
||||
const Janet *form = janet_unwrap_tuple(x);
|
||||
if (janet_tuple_length(form) == 0)
|
||||
return 0;
|
||||
/* Source map - only set when we get a tuple */
|
||||
if (janet_tuple_sm_start(form) >= 0) {
|
||||
c->current_mapping.start = janet_tuple_sm_start(form);
|
||||
c->current_mapping.end = janet_tuple_sm_end(form);
|
||||
if (janet_tuple_sm_line(form) >= 0) {
|
||||
c->current_mapping.line = janet_tuple_sm_line(form);
|
||||
c->current_mapping.column = janet_tuple_sm_column(form);
|
||||
}
|
||||
/* Bracketed tuples are not specials or macros! */
|
||||
if (janet_tuple_flag(form) & JANET_TUPLE_FLAG_BRACKETCTOR)
|
||||
return 0;
|
||||
if (!janet_checktype(form[0], JANET_SYMBOL))
|
||||
return 0;
|
||||
const uint8_t *name = janet_unwrap_symbol(form[0]);
|
||||
@@ -481,27 +721,47 @@ static int macroexpand1(
|
||||
}
|
||||
Janet macroval;
|
||||
JanetBindingType btype = janet_resolve(c->env, name, ¯oval);
|
||||
if (btype != JANET_BINDING_MACRO ||
|
||||
if (!(btype == JANET_BINDING_MACRO || btype == JANET_BINDING_DYNAMIC_MACRO) ||
|
||||
!janet_checktype(macroval, JANET_FUNCTION))
|
||||
return 0;
|
||||
|
||||
/* Evaluate macro */
|
||||
JanetFiber *fiberp;
|
||||
JanetFunction *macro = janet_unwrap_function(macroval);
|
||||
int32_t arity = janet_tuple_length(form) - 1;
|
||||
JanetFiber *fiberp = janet_fiber(macro, 64, arity, form + 1);
|
||||
if (NULL == fiberp) {
|
||||
int32_t minar = macro->def->min_arity;
|
||||
int32_t maxar = macro->def->max_arity;
|
||||
const uint8_t *es = NULL;
|
||||
if (minar >= 0 && arity < minar)
|
||||
es = janet_formatc("macro arity mismatch, expected at least %d, got %d", minar, arity);
|
||||
if (maxar >= 0 && arity > maxar)
|
||||
es = janet_formatc("macro arity mismatch, expected at most %d, got %d", maxar, arity);
|
||||
c->result.macrofiber = NULL;
|
||||
janetc_error(c, es);
|
||||
return 0;
|
||||
}
|
||||
/* Set env */
|
||||
fiberp->env = c->env;
|
||||
int lock = janet_gclock();
|
||||
JanetSignal status = janet_pcall(
|
||||
macro,
|
||||
janet_tuple_length(form) - 1,
|
||||
form + 1,
|
||||
&x,
|
||||
&fiberp);
|
||||
Janet mf_kw = janet_ckeywordv("macro-form");
|
||||
janet_table_put(c->env, mf_kw, x);
|
||||
Janet ml_kw = janet_ckeywordv("macro-lints");
|
||||
if (c->lints) {
|
||||
janet_table_put(c->env, ml_kw, janet_wrap_array(c->lints));
|
||||
}
|
||||
Janet tempOut;
|
||||
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
|
||||
janet_table_put(c->env, mf_kw, janet_wrap_nil());
|
||||
janet_table_put(c->env, ml_kw, janet_wrap_nil());
|
||||
janet_gcunlock(lock);
|
||||
if (status != JANET_SIGNAL_OK) {
|
||||
const uint8_t *es = janet_formatc("(macro) %V", x);
|
||||
const uint8_t *es = janet_formatc("(macro) %V", tempOut);
|
||||
c->result.macrofiber = fiberp;
|
||||
janetc_error(c, es);
|
||||
return 0;
|
||||
} else {
|
||||
*out = x;
|
||||
*out = tempOut;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -540,22 +800,23 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
|
||||
ret = spec->compile(opts, janet_tuple_length(tup) - 1, tup + 1);
|
||||
} else {
|
||||
switch (janet_type(x)) {
|
||||
case JANET_TUPLE:
|
||||
{
|
||||
JanetFopts subopts = janetc_fopts_default(c);
|
||||
const Janet *tup = janet_unwrap_tuple(x);
|
||||
/* Empty tuple is tuple literal */
|
||||
if (janet_tuple_length(tup) == 0) {
|
||||
ret = janetc_cslot(x);
|
||||
} else {
|
||||
JanetSlot head = janetc_value(subopts, tup[0]);
|
||||
subopts.flags = JANET_FUNCTION | JANET_CFUNCTION;
|
||||
ret = janetc_call(opts, janetc_toslots(c, tup + 1, janet_tuple_length(tup) - 1), head);
|
||||
janetc_freeslot(c, head);
|
||||
}
|
||||
ret.flags &= ~JANET_SLOT_SPLICED;
|
||||
case JANET_TUPLE: {
|
||||
JanetFopts subopts = janetc_fopts_default(c);
|
||||
const Janet *tup = janet_unwrap_tuple(x);
|
||||
/* Empty tuple is tuple literal */
|
||||
if (janet_tuple_length(tup) == 0) {
|
||||
ret = janetc_cslot(janet_wrap_tuple(janet_tuple_n(NULL, 0)));
|
||||
} else if (janet_tuple_flag(tup) & JANET_TUPLE_FLAG_BRACKETCTOR) { /* [] tuples are not function call */
|
||||
ret = janetc_tuple(opts, x);
|
||||
} else {
|
||||
JanetSlot head = janetc_value(subopts, tup[0]);
|
||||
subopts.flags = JANET_FUNCTION | JANET_CFUNCTION;
|
||||
ret = janetc_call(opts, janetc_toslots(c, tup + 1, janet_tuple_length(tup) - 1), head);
|
||||
janetc_freeslot(c, head);
|
||||
}
|
||||
break;
|
||||
ret.flags &= ~JANET_SLOT_SPLICED;
|
||||
}
|
||||
break;
|
||||
case JANET_SYMBOL:
|
||||
ret = janetc_resolve(c, janet_unwrap_symbol(x));
|
||||
break;
|
||||
@@ -590,7 +851,32 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add function flags to janet functions */
|
||||
void janet_def_addflags(JanetFuncDef *def) {
|
||||
int32_t set_flags = 0;
|
||||
int32_t unset_flags = 0;
|
||||
/* pos checks */
|
||||
if (def->name) set_flags |= JANET_FUNCDEF_FLAG_HASNAME;
|
||||
if (def->source) set_flags |= JANET_FUNCDEF_FLAG_HASSOURCE;
|
||||
if (def->defs) set_flags |= JANET_FUNCDEF_FLAG_HASDEFS;
|
||||
if (def->environments) set_flags |= JANET_FUNCDEF_FLAG_HASENVS;
|
||||
if (def->sourcemap) set_flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
|
||||
if (def->closure_bitset) set_flags |= JANET_FUNCDEF_FLAG_HASCLOBITSET;
|
||||
/* negative checks */
|
||||
if (!def->name) unset_flags |= JANET_FUNCDEF_FLAG_HASNAME;
|
||||
if (!def->source) unset_flags |= JANET_FUNCDEF_FLAG_HASSOURCE;
|
||||
if (!def->defs) unset_flags |= JANET_FUNCDEF_FLAG_HASDEFS;
|
||||
if (!def->environments) unset_flags |= JANET_FUNCDEF_FLAG_HASENVS;
|
||||
if (!def->sourcemap) unset_flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
|
||||
if (!def->closure_bitset) unset_flags |= JANET_FUNCDEF_FLAG_HASCLOBITSET;
|
||||
/* Update flags */
|
||||
def->flags |= set_flags;
|
||||
def->flags &= ~unset_flags;
|
||||
}
|
||||
|
||||
/* Compile a funcdef */
|
||||
/* Once the various other settings of the FuncDef have been tweaked,
|
||||
* call janet_def_addflags to set the proper flags for the funcdef */
|
||||
JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
|
||||
JanetScope *scope = c->scope;
|
||||
JanetFuncDef *def = janet_funcdef_alloc();
|
||||
@@ -600,7 +886,10 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
|
||||
|
||||
/* Copy envs */
|
||||
def->environments_length = janet_v_count(scope->envs);
|
||||
def->environments = janet_v_flatten(scope->envs);
|
||||
def->environments = janet_malloc(sizeof(int32_t) * def->environments_length);
|
||||
for (int32_t i = 0; i < def->environments_length; i++) {
|
||||
def->environments[i] = scope->envs[i].envindex;
|
||||
}
|
||||
|
||||
def->constants_length = janet_v_count(scope->consts);
|
||||
def->constants = janet_v_flatten(scope->consts);
|
||||
@@ -611,20 +900,20 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
|
||||
/* Copy bytecode (only last chunk) */
|
||||
def->bytecode_length = janet_v_count(c->buffer) - scope->bytecode_start;
|
||||
if (def->bytecode_length) {
|
||||
size_t s = sizeof(int32_t) * def->bytecode_length;
|
||||
def->bytecode = malloc(s);
|
||||
size_t s = sizeof(int32_t) * (size_t) def->bytecode_length;
|
||||
def->bytecode = janet_malloc(s);
|
||||
if (NULL == def->bytecode) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
|
||||
safe_memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
|
||||
janet_v__cnt(c->buffer) = scope->bytecode_start;
|
||||
if (NULL != c->mapbuffer) {
|
||||
size_t s = sizeof(JanetSourceMapping) * def->bytecode_length;
|
||||
def->sourcemap = malloc(s);
|
||||
if (NULL != c->mapbuffer && c->source) {
|
||||
size_t s = sizeof(JanetSourceMapping) * (size_t) def->bytecode_length;
|
||||
def->sourcemap = janet_malloc(s);
|
||||
if (NULL == def->sourcemap) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(def->sourcemap, c->mapbuffer + scope->bytecode_start, s);
|
||||
safe_memcpy(def->sourcemap, c->mapbuffer + scope->bytecode_start, s);
|
||||
janet_v__cnt(c->mapbuffer) = scope->bytecode_start;
|
||||
}
|
||||
}
|
||||
@@ -633,34 +922,109 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
|
||||
def->source = c->source;
|
||||
|
||||
def->arity = 0;
|
||||
def->min_arity = 0;
|
||||
def->flags = 0;
|
||||
if (scope->flags & JANET_SCOPE_ENV) {
|
||||
def->flags |= JANET_FUNCDEF_FLAG_NEEDSENV;
|
||||
}
|
||||
|
||||
/* Copy upvalue bitset */
|
||||
if (scope->ua.count) {
|
||||
/* Number of u32s we need to create a bitmask for all slots */
|
||||
int32_t slotchunks = (def->slotcount + 31) >> 5;
|
||||
/* numchunks is min of slotchunks and scope->ua.count */
|
||||
int32_t numchunks = slotchunks > scope->ua.count ? scope->ua.count : slotchunks;
|
||||
uint32_t *chunks = janet_calloc(sizeof(uint32_t), slotchunks);
|
||||
if (NULL == chunks) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(chunks, scope->ua.chunks, sizeof(uint32_t) * numchunks);
|
||||
/* Register allocator preallocates some registers [240-255, high 16 bits of chunk index 7], we can ignore those. */
|
||||
if (scope->ua.count > 7) chunks[7] &= 0xFFFFU;
|
||||
def->closure_bitset = chunks;
|
||||
}
|
||||
|
||||
/* Capture symbol to local mapping */
|
||||
JanetSymbolMap *locals = NULL;
|
||||
|
||||
/* Symbol -> upvalue mapping */
|
||||
JanetScope *top = c->scope;
|
||||
while (top->parent) top = top->parent;
|
||||
for (JanetScope *s = top; s != NULL; s = s->child) {
|
||||
for (int32_t j = 0; j < janet_v_count(scope->envs); j++) {
|
||||
JanetEnvRef ref = scope->envs[j];
|
||||
JanetScope *upscope = ref.scope;
|
||||
if (upscope != s) continue;
|
||||
for (int32_t i = 0; i < janet_v_count(upscope->syms); i++) {
|
||||
SymPair pair = upscope->syms[i];
|
||||
if (pair.sym2) {
|
||||
JanetSymbolMap jsm;
|
||||
jsm.birth_pc = UINT32_MAX;
|
||||
jsm.death_pc = j;
|
||||
jsm.slot_index = pair.slot.index;
|
||||
jsm.symbol = pair.sym2;
|
||||
janet_v_push(locals, jsm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Symbol -> slot mapping */
|
||||
for (int32_t i = 0; i < janet_v_count(scope->syms); i++) {
|
||||
SymPair pair = scope->syms[i];
|
||||
if (pair.sym2) {
|
||||
JanetSymbolMap jsm;
|
||||
if (pair.death_pc == UINT32_MAX) {
|
||||
jsm.death_pc = def->bytecode_length;
|
||||
} else {
|
||||
jsm.death_pc = pair.death_pc - scope->bytecode_start;
|
||||
}
|
||||
/* Handle birth_pc == 0 correctly */
|
||||
if ((uint32_t) scope->bytecode_start > pair.birth_pc) {
|
||||
jsm.birth_pc = 0;
|
||||
} else {
|
||||
jsm.birth_pc = pair.birth_pc - scope->bytecode_start;
|
||||
}
|
||||
janet_assert(jsm.birth_pc <= jsm.death_pc, "birth pc after death pc");
|
||||
janet_assert(jsm.birth_pc < (uint32_t) def->bytecode_length, "bad birth pc");
|
||||
janet_assert(jsm.death_pc <= (uint32_t) def->bytecode_length, "bad death pc");
|
||||
jsm.slot_index = pair.slot.index;
|
||||
jsm.symbol = pair.sym2;
|
||||
janet_v_push(locals, jsm);
|
||||
}
|
||||
}
|
||||
def->symbolmap_length = janet_v_count(locals);
|
||||
def->symbolmap = janet_v_flatten(locals);
|
||||
if (def->symbolmap_length) def->flags |= JANET_FUNCDEF_FLAG_HASSYMBOLMAP;
|
||||
|
||||
/* Pop the scope */
|
||||
janetc_popscope(c);
|
||||
|
||||
/* Do basic optimization */
|
||||
janet_bytecode_movopt(def);
|
||||
janet_bytecode_remove_noops(def);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
/* Initialize a compiler */
|
||||
static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where) {
|
||||
static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where, JanetArray *lints) {
|
||||
c->scope = NULL;
|
||||
c->buffer = NULL;
|
||||
c->mapbuffer = NULL;
|
||||
c->recursion_guard = JANET_RECURSION_GUARD;
|
||||
c->env = env;
|
||||
c->source = where;
|
||||
c->current_mapping.start = -1;
|
||||
c->current_mapping.end = -1;
|
||||
c->current_mapping.line = -1;
|
||||
c->current_mapping.column = -1;
|
||||
c->lints = lints;
|
||||
/* Init result */
|
||||
c->result.error = NULL;
|
||||
c->result.status = JANET_COMPILE_OK;
|
||||
c->result.funcdef = NULL;
|
||||
c->result.macrofiber = NULL;
|
||||
c->result.error_mapping.start = -1;
|
||||
c->result.error_mapping.end = -1;
|
||||
c->result.error_mapping.line = -1;
|
||||
c->result.error_mapping.column = -1;
|
||||
}
|
||||
|
||||
/* Deinitialize a compiler struct */
|
||||
@@ -671,12 +1035,13 @@ static void janetc_deinit(JanetCompiler *c) {
|
||||
}
|
||||
|
||||
/* Compile a form. */
|
||||
JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where) {
|
||||
JanetCompileResult janet_compile_lint(Janet source,
|
||||
JanetTable *env, const uint8_t *where, JanetArray *lints) {
|
||||
JanetCompiler c;
|
||||
JanetScope rootscope;
|
||||
JanetFopts fopts;
|
||||
|
||||
janetc_init(&c, env, where);
|
||||
janetc_init(&c, env, where, lints);
|
||||
|
||||
/* Push a function scope */
|
||||
janetc_scope(&rootscope, &c, JANET_SCOPE_FUNCTION | JANET_SCOPE_TOP, "root");
|
||||
@@ -692,6 +1057,7 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
|
||||
if (c.result.status == JANET_COMPILE_OK) {
|
||||
JanetFuncDef *def = janetc_pop_funcdef(&c);
|
||||
def->name = janet_cstring("_thunk");
|
||||
janet_def_addflags(def);
|
||||
c.result.funcdef = def;
|
||||
} else {
|
||||
c.result.error_mapping = c.current_mapping;
|
||||
@@ -703,22 +1069,51 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
|
||||
return c.result;
|
||||
}
|
||||
|
||||
JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where) {
|
||||
return janet_compile_lint(source, env, where, NULL);
|
||||
}
|
||||
|
||||
/* C Function for compiling */
|
||||
static Janet cfun(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetTable *env = janet_gettable(argv, 1);
|
||||
const uint8_t *source = NULL;
|
||||
if (argc == 3) {
|
||||
source = janet_getstring(argv, 2);
|
||||
JANET_CORE_FN(cfun_compile,
|
||||
"(compile ast &opt env source lints)",
|
||||
"Compiles an Abstract Syntax Tree (ast) into a function. "
|
||||
"Pair the compile function with parsing functionality to implement "
|
||||
"eval. Returns a new function and does not modify ast. Returns an error "
|
||||
"struct with keys :line, :column, and :error if compilation fails. "
|
||||
"If a `lints` array is given, linting messages will be appended to the array. "
|
||||
"Each message will be a tuple of the form `(level line col message)`.") {
|
||||
janet_arity(argc, 1, 4);
|
||||
JanetTable *env = (argc > 1 && !janet_checktype(argv[1], JANET_NIL))
|
||||
? janet_gettable(argv, 1) : janet_vm.fiber->env;
|
||||
if (NULL == env) {
|
||||
env = janet_table(0);
|
||||
janet_vm.fiber->env = env;
|
||||
}
|
||||
JanetCompileResult res = janet_compile(argv[0], env, source);
|
||||
const uint8_t *source = NULL;
|
||||
if (argc >= 3) {
|
||||
Janet x = argv[2];
|
||||
if (janet_checktype(x, JANET_STRING)) {
|
||||
source = janet_unwrap_string(x);
|
||||
} else if (janet_checktype(x, JANET_KEYWORD)) {
|
||||
source = janet_unwrap_keyword(x);
|
||||
} else if (!janet_checktype(x, JANET_NIL)) {
|
||||
janet_panic_type(x, 2, JANET_TFLAG_STRING | JANET_TFLAG_KEYWORD);
|
||||
}
|
||||
}
|
||||
JanetArray *lints = (argc >= 4 && !janet_checktype(argv[3], JANET_NIL))
|
||||
? janet_getarray(argv, 3) : NULL;
|
||||
JanetCompileResult res = janet_compile_lint(argv[0], env, source, lints);
|
||||
if (res.status == JANET_COMPILE_OK) {
|
||||
return janet_wrap_function(janet_thunk(res.funcdef));
|
||||
} else {
|
||||
JanetTable *t = janet_table(4);
|
||||
janet_table_put(t, janet_ckeywordv("error"), janet_wrap_string(res.error));
|
||||
janet_table_put(t, janet_ckeywordv("start"), janet_wrap_integer(res.error_mapping.start));
|
||||
janet_table_put(t, janet_ckeywordv("end"), janet_wrap_integer(res.error_mapping.end));
|
||||
if (res.error_mapping.line > 0) {
|
||||
janet_table_put(t, janet_ckeywordv("line"), janet_wrap_integer(res.error_mapping.line));
|
||||
}
|
||||
if (res.error_mapping.column > 0) {
|
||||
janet_table_put(t, janet_ckeywordv("column"), janet_wrap_integer(res.error_mapping.column));
|
||||
}
|
||||
if (res.macrofiber) {
|
||||
janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber));
|
||||
}
|
||||
@@ -726,17 +1121,10 @@ static Janet cfun(int32_t argc, Janet *argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static const JanetReg compile_cfuns[] = {
|
||||
{"compile", cfun,
|
||||
JDOC("(compile ast env [, source])\n\n"
|
||||
"Compiles an Abstract Syntax Tree (ast) into a janet function. "
|
||||
"Pair the compile function with parsing functionality to implement "
|
||||
"eval. Returns a janet function and does not modify ast. Throws an "
|
||||
"error if the ast cannot be compiled.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void janet_lib_compile(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, compile_cfuns);
|
||||
JanetRegExt cfuns[] = {
|
||||
JANET_CORE_REG("compile", cfun_compile),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, cfuns);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -24,17 +24,25 @@
|
||||
#define JANET_COMPILE_H
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "regalloc.h"
|
||||
#endif
|
||||
|
||||
/* Levels for compiler warnings */
|
||||
typedef enum {
|
||||
JANET_C_LINT_RELAXED,
|
||||
JANET_C_LINT_NORMAL,
|
||||
JANET_C_LINT_STRICT
|
||||
} JanetCompileLintLevel;
|
||||
|
||||
/* Tags for some functions for the prepared inliner */
|
||||
#define JANET_FUN_DEBUG 1
|
||||
#define JANET_FUN_ERROR 2
|
||||
#define JANET_FUN_APPLY 3
|
||||
#define JANET_FUN_YIELD 4
|
||||
#define JANET_FUN_RESUME 5
|
||||
#define JANET_FUN_GET 6
|
||||
#define JANET_FUN_IN 6
|
||||
#define JANET_FUN_PUT 7
|
||||
#define JANET_FUN_LENGTH 8
|
||||
#define JANET_FUN_ADD 9
|
||||
@@ -48,18 +56,20 @@
|
||||
#define JANET_FUN_RSHIFT 17
|
||||
#define JANET_FUN_RSHIFTU 18
|
||||
#define JANET_FUN_BNOT 19
|
||||
#define JANET_FUN_ORDER_GT 20
|
||||
#define JANET_FUN_ORDER_LT 21
|
||||
#define JANET_FUN_ORDER_GTE 22
|
||||
#define JANET_FUN_ORDER_LTE 23
|
||||
#define JANET_FUN_ORDER_EQ 24
|
||||
#define JANET_FUN_ORDER_NEQ 25
|
||||
#define JANET_FUN_GT 26
|
||||
#define JANET_FUN_LT 27
|
||||
#define JANET_FUN_GTE 28
|
||||
#define JANET_FUN_LTE 29
|
||||
#define JANET_FUN_EQ 30
|
||||
#define JANET_FUN_NEQ 31
|
||||
#define JANET_FUN_GT 20
|
||||
#define JANET_FUN_LT 21
|
||||
#define JANET_FUN_GTE 22
|
||||
#define JANET_FUN_LTE 23
|
||||
#define JANET_FUN_EQ 24
|
||||
#define JANET_FUN_NEQ 25
|
||||
#define JANET_FUN_PROP 26
|
||||
#define JANET_FUN_GET 27
|
||||
#define JANET_FUN_NEXT 28
|
||||
#define JANET_FUN_MODULO 29
|
||||
#define JANET_FUN_REMAINDER 30
|
||||
#define JANET_FUN_CMP 31
|
||||
#define JANET_FUN_CANCEL 32
|
||||
#define JANET_FUN_DIVIDE_FLOOR 33
|
||||
|
||||
/* Compiler typedefs */
|
||||
typedef struct JanetCompiler JanetCompiler;
|
||||
@@ -76,10 +86,10 @@ typedef struct JanetSpecial JanetSpecial;
|
||||
#define JANET_SLOT_MUTABLE 0x40000
|
||||
#define JANET_SLOT_REF 0x80000
|
||||
#define JANET_SLOT_RETURNED 0x100000
|
||||
/* Needed for handling single element arrays as global vars. */
|
||||
|
||||
/* Used for unquote-splicing */
|
||||
#define JANET_SLOT_SPLICED 0x200000
|
||||
#define JANET_SLOT_DEP_NOTE 0x200000
|
||||
#define JANET_SLOT_DEP_WARN 0x400000
|
||||
#define JANET_SLOT_DEP_ERROR 0x800000
|
||||
#define JANET_SLOT_SPLICED 0x1000000
|
||||
|
||||
#define JANET_SLOTTYPE_ANY 0xFFFF
|
||||
|
||||
@@ -96,18 +106,27 @@ struct JanetSlot {
|
||||
#define JANET_SCOPE_TOP 4
|
||||
#define JANET_SCOPE_UNUSED 8
|
||||
#define JANET_SCOPE_CLOSURE 16
|
||||
#define JANET_SCOPE_WHILE 32
|
||||
|
||||
/* A symbol and slot pair */
|
||||
typedef struct SymPair {
|
||||
JanetSlot slot;
|
||||
const uint8_t *sym;
|
||||
const uint8_t *sym2;
|
||||
int keep;
|
||||
uint32_t birth_pc;
|
||||
uint32_t death_pc;
|
||||
} SymPair;
|
||||
|
||||
typedef struct JanetEnvRef {
|
||||
int32_t envindex;
|
||||
JanetScope *scope;
|
||||
} JanetEnvRef;
|
||||
|
||||
/* A lexical scope during compilation */
|
||||
struct JanetScope {
|
||||
|
||||
/* For debugging */
|
||||
/* For debugging the compiler */
|
||||
const char *name;
|
||||
|
||||
/* Scopes are doubly linked list */
|
||||
@@ -123,16 +142,16 @@ struct JanetScope {
|
||||
/* FuncDefs */
|
||||
JanetFuncDef **defs;
|
||||
|
||||
/* Regsiter allocator */
|
||||
/* Register allocator */
|
||||
JanetcRegisterAllocator ra;
|
||||
|
||||
/* Referenced closure environents. The values at each index correspond
|
||||
/* Upvalue allocator */
|
||||
JanetcRegisterAllocator ua;
|
||||
|
||||
/* Referenced closure environments. The values at each index correspond
|
||||
* to which index to get the environment from in the parent. The environment
|
||||
* that corresponds to the direct parent's stack will always have value 0. */
|
||||
int32_t *envs;
|
||||
|
||||
/* Where to add reference to self in constants */
|
||||
int32_t selfconst;
|
||||
JanetEnvRef *envs;
|
||||
|
||||
int32_t bytecode_start;
|
||||
int flags;
|
||||
@@ -161,11 +180,15 @@ struct JanetCompiler {
|
||||
|
||||
/* Prevent unbounded recursion */
|
||||
int recursion_guard;
|
||||
|
||||
/* Collect linting results */
|
||||
JanetArray *lints;
|
||||
};
|
||||
|
||||
#define JANET_FOPTS_TAIL 0x10000
|
||||
#define JANET_FOPTS_HINT 0x20000
|
||||
#define JANET_FOPTS_DROP 0x40000
|
||||
#define JANET_FOPTS_ACCEPT_SPLICE 0x80000
|
||||
|
||||
/* Options for compiling a single form */
|
||||
struct JanetFopts {
|
||||
@@ -180,13 +203,13 @@ JanetFopts janetc_fopts_default(JanetCompiler *c);
|
||||
/* For optimizing builtin normal functions. */
|
||||
struct JanetFunOptimizer {
|
||||
int (*can_optimize)(JanetFopts opts, JanetSlot *args);
|
||||
JanetSlot (*optimize)(JanetFopts opts, JanetSlot *args);
|
||||
JanetSlot(*optimize)(JanetFopts opts, JanetSlot *args);
|
||||
};
|
||||
|
||||
/* A grouping of a named special and the corresponding compiler fragment */
|
||||
struct JanetSpecial {
|
||||
const char *name;
|
||||
JanetSlot (*compile)(JanetFopts opts, int32_t argn, const Janet *argv);
|
||||
JanetSlot(*compile)(JanetFopts opts, int32_t argn, const Janet *argv);
|
||||
};
|
||||
|
||||
/****************************************************/
|
||||
@@ -214,8 +237,8 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len);
|
||||
/* Get a bunch of slots for function arguments */
|
||||
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds);
|
||||
|
||||
/* Push slots load via janetc_toslots. */
|
||||
void janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
|
||||
/* Push slots loaded via janetc_toslots. */
|
||||
int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
|
||||
|
||||
/* Free slots loaded via janetc_toslots */
|
||||
void janetc_freeslots(JanetCompiler *c, JanetSlot *slots);
|
||||
@@ -227,6 +250,9 @@ JanetSlot janetc_return(JanetCompiler *c, JanetSlot s);
|
||||
void janetc_error(JanetCompiler *c, const uint8_t *m);
|
||||
void janetc_cerror(JanetCompiler *c, const char *m);
|
||||
|
||||
/* Linting */
|
||||
void janetc_lintf(JanetCompiler *C, JanetCompileLintLevel level, const char *format, ...);
|
||||
|
||||
/* Dispatch to correct form compiler */
|
||||
JanetSlot janetc_value(JanetFopts opts, Janet x);
|
||||
|
||||
@@ -242,4 +268,8 @@ JanetSlot janetc_cslot(Janet x);
|
||||
/* Search for a symbol */
|
||||
JanetSlot janetc_resolve(JanetCompiler *c, const uint8_t *sym);
|
||||
|
||||
/* Bytecode optimization */
|
||||
void janet_bytecode_movopt(JanetFuncDef *def);
|
||||
void janet_bytecode_remove_noops(JanetFuncDef *def);
|
||||
|
||||
#endif
|
||||
|
||||
1725
src/core/core.janet
1725
src/core/core.janet
File diff suppressed because it is too large
Load Diff
1362
src/core/corelib.c
1362
src/core/corelib.c
File diff suppressed because it is too large
Load Diff
321
src/core/debug.c
321
src/core/debug.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "state.h"
|
||||
#include "util.h"
|
||||
@@ -51,37 +52,41 @@ void janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
|
||||
* location.
|
||||
*/
|
||||
void janet_debug_find(
|
||||
JanetFuncDef **def_out, int32_t *pc_out,
|
||||
const uint8_t *source, int32_t offset) {
|
||||
JanetFuncDef **def_out, int32_t *pc_out,
|
||||
const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) {
|
||||
/* Scan the heap for right func def */
|
||||
JanetGCMemoryHeader *current = janet_vm_blocks;
|
||||
JanetGCObject *current = janet_vm.blocks;
|
||||
/* Keep track of the best source mapping we have seen so far */
|
||||
int32_t besti = -1;
|
||||
int32_t best_range = INT32_MAX;
|
||||
int32_t best_line = -1;
|
||||
int32_t best_column = -1;
|
||||
JanetFuncDef *best_def = NULL;
|
||||
while (NULL != current) {
|
||||
if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) {
|
||||
JanetFuncDef *def = (JanetFuncDef *)(current + 1);
|
||||
JanetFuncDef *def = (JanetFuncDef *)(current);
|
||||
if (def->sourcemap &&
|
||||
def->source &&
|
||||
!janet_string_compare(source, def->source)) {
|
||||
/* Correct source file, check mappings. The chosen
|
||||
* pc index is the first match with the smallest range. */
|
||||
* pc index is the instruction closest to the given line column, but
|
||||
* not after. */
|
||||
int32_t i;
|
||||
for (i = 0; i < def->bytecode_length; i++) {
|
||||
int32_t start = def->sourcemap[i].start;
|
||||
int32_t end = def->sourcemap[i].end;
|
||||
if (end - start < best_range &&
|
||||
start <= offset &&
|
||||
end >= offset) {
|
||||
best_range = end - start;
|
||||
besti = i;
|
||||
best_def = def;
|
||||
int32_t line = def->sourcemap[i].line;
|
||||
int32_t column = def->sourcemap[i].column;
|
||||
if (line <= sourceLine && line >= best_line) {
|
||||
if (column <= sourceColumn &&
|
||||
(line > best_line || column > best_column)) {
|
||||
best_line = line;
|
||||
best_column = column;
|
||||
besti = i;
|
||||
best_def = def;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
current = current->next;
|
||||
current = current->data.next;
|
||||
}
|
||||
if (best_def) {
|
||||
*def_out = best_def;
|
||||
@@ -91,13 +96,22 @@ void janet_debug_find(
|
||||
}
|
||||
}
|
||||
|
||||
void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
const char *prefix = janet_checktype(err, JANET_NIL) ? NULL : "";
|
||||
janet_stacktrace_ext(fiber, err, prefix);
|
||||
}
|
||||
|
||||
/* Error reporting. This can be emulated from within Janet, but for
|
||||
* consitency with the top level code it is defined once. */
|
||||
void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix) {
|
||||
|
||||
int32_t fi;
|
||||
const char *errstr = (const char *)janet_to_string(err);
|
||||
JanetFiber **fibers = NULL;
|
||||
int wrote_error = 0;
|
||||
int wrote_error = !prefix;
|
||||
|
||||
int print_color = janet_truthy(janet_dyn("err-color"));
|
||||
if (print_color) janet_eprintf("\x1b[31m");
|
||||
|
||||
while (fiber) {
|
||||
janet_v_push(fibers, fiber);
|
||||
@@ -108,6 +122,7 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
fiber = fibers[fi];
|
||||
int32_t i = fiber->frame;
|
||||
while (i > 0) {
|
||||
JanetCFunRegistry *reg = NULL;
|
||||
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
JanetFuncDef *def = NULL;
|
||||
i = frame->prevframe;
|
||||
@@ -115,47 +130,61 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
/* Print prelude to stack frame */
|
||||
if (!wrote_error) {
|
||||
JanetFiberStatus status = janet_fiber_status(fiber);
|
||||
const char *prefix = status == JANET_STATUS_ERROR ? "" : "status ";
|
||||
fprintf(stderr, "%s%s: %s\n",
|
||||
prefix,
|
||||
janet_status_names[status],
|
||||
errstr);
|
||||
janet_eprintf("%s%s: %s\n",
|
||||
prefix ? prefix : "",
|
||||
janet_status_names[status],
|
||||
errstr ? errstr : janet_status_names[status]);
|
||||
wrote_error = 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, " in");
|
||||
janet_eprintf(" in");
|
||||
|
||||
if (frame->func) {
|
||||
def = frame->func->def;
|
||||
fprintf(stderr, " %s", def->name ? (const char *)def->name : "<anonymous>");
|
||||
janet_eprintf(" %s", def->name ? (const char *)def->name : "<anonymous>");
|
||||
if (def->source) {
|
||||
fprintf(stderr, " [%s]", (const char *)def->source);
|
||||
janet_eprintf(" [%s]", (const char *)def->source);
|
||||
}
|
||||
} else {
|
||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||
if (cfun) {
|
||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||
if (!janet_checktype(name, JANET_NIL))
|
||||
fprintf(stderr, " %s", (const char *)janet_to_string(name));
|
||||
else
|
||||
fprintf(stderr, " <cfunction>");
|
||||
reg = janet_registry_get(cfun);
|
||||
if (NULL != reg && NULL != reg->name) {
|
||||
if (reg->name_prefix) {
|
||||
janet_eprintf(" %s/%s", reg->name_prefix, reg->name);
|
||||
} else {
|
||||
janet_eprintf(" %s", reg->name);
|
||||
}
|
||||
if (NULL != reg->source_file) {
|
||||
janet_eprintf(" [%s]", reg->source_file);
|
||||
}
|
||||
} else {
|
||||
janet_eprintf(" <cfunction>");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL)
|
||||
fprintf(stderr, " (tailcall)");
|
||||
janet_eprintf(" (tailcall)");
|
||||
if (frame->func && frame->pc) {
|
||||
int32_t off = (int32_t) (frame->pc - def->bytecode);
|
||||
int32_t off = (int32_t)(frame->pc - def->bytecode);
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end);
|
||||
janet_eprintf(" on line %d, column %d", mapping.line, mapping.column);
|
||||
} else {
|
||||
fprintf(stderr, " pc=%d", off);
|
||||
janet_eprintf(" pc=%d", off);
|
||||
}
|
||||
} else if (NULL != reg) {
|
||||
/* C Function */
|
||||
if (reg->source_line > 0) {
|
||||
janet_eprintf(" on line %d", (long) reg->source_line);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
janet_eprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (print_color) janet_eprintf("\x1b[0m");
|
||||
|
||||
janet_v_free(fibers);
|
||||
}
|
||||
|
||||
@@ -166,10 +195,11 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
|
||||
* Takes a source file name and byte offset. */
|
||||
static void helper_find(int32_t argc, Janet *argv, JanetFuncDef **def, int32_t *bytecode_offset) {
|
||||
janet_fixarity(argc, 2);
|
||||
janet_fixarity(argc, 3);
|
||||
const uint8_t *source = janet_getstring(argv, 0);
|
||||
int32_t source_offset = janet_getinteger(argv, 1);
|
||||
janet_debug_find(def, bytecode_offset, source, source_offset);
|
||||
int32_t line = janet_getinteger(argv, 1);
|
||||
int32_t col = janet_getinteger(argv, 2);
|
||||
janet_debug_find(def, bytecode_offset, source, line, col);
|
||||
}
|
||||
|
||||
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
|
||||
@@ -182,7 +212,13 @@ static void helper_find_fun(int32_t argc, Janet *argv, JanetFuncDef **def, int32
|
||||
*bytecode_offset = offset;
|
||||
}
|
||||
|
||||
static Janet cfun_debug_break(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_break,
|
||||
"(debug/break source line col)",
|
||||
"Sets a breakpoint in `source` at a given line and column. "
|
||||
"Will throw an error if the breakpoint location "
|
||||
"cannot be found. For example\n\n"
|
||||
"\t(debug/break \"core.janet\" 10 4)\n\n"
|
||||
"will set a breakpoint at line 10, 4th column of the file core.janet.") {
|
||||
JanetFuncDef *def;
|
||||
int32_t offset;
|
||||
helper_find(argc, argv, &def, &offset);
|
||||
@@ -190,23 +226,33 @@ static Janet cfun_debug_break(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_unbreak,
|
||||
"(debug/unbreak source line column)",
|
||||
"Remove a breakpoint with a source key at a given line and column. "
|
||||
"Will throw an error if the breakpoint "
|
||||
"cannot be found.") {
|
||||
JanetFuncDef *def;
|
||||
int32_t offset;
|
||||
int32_t offset = 0;
|
||||
helper_find(argc, argv, &def, &offset);
|
||||
janet_debug_unbreak(def, offset);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_debug_fbreak(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_fbreak,
|
||||
"(debug/fbreak fun &opt pc)",
|
||||
"Set a breakpoint in a given function. pc is an optional offset, which "
|
||||
"is in bytecode instructions. fun is a function value. Will throw an error "
|
||||
"if the offset is too large or negative.") {
|
||||
JanetFuncDef *def;
|
||||
int32_t offset;
|
||||
int32_t offset = 0;
|
||||
helper_find_fun(argc, argv, &def, &offset);
|
||||
janet_debug_break(def, offset);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_unfbreak,
|
||||
"(debug/unfbreak fun &opt pc)",
|
||||
"Unset a breakpoint set with debug/fbreak.") {
|
||||
JanetFuncDef *def;
|
||||
int32_t offset;
|
||||
helper_find_fun(argc, argv, &def, &offset);
|
||||
@@ -214,7 +260,12 @@ static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_debug_lineage(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_lineage,
|
||||
"(debug/lineage fib)",
|
||||
"Returns an array of all child fibers from a root fiber. This function "
|
||||
"is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
|
||||
"the fiber handling the error can see which fiber raised the signal. This function should "
|
||||
"be used mostly for debugging purposes.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
JanetArray *array = janet_array(0);
|
||||
@@ -239,9 +290,20 @@ static Janet doframe(JanetStackFrame *frame) {
|
||||
} else {
|
||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||
if (cfun) {
|
||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||
if (!janet_checktype(name, JANET_NIL)) {
|
||||
janet_table_put(t, janet_ckeywordv("name"), name);
|
||||
JanetCFunRegistry *reg = janet_registry_get(cfun);
|
||||
if (NULL != reg->name) {
|
||||
if (NULL != reg->name_prefix) {
|
||||
janet_table_put(t, janet_ckeywordv("name"), janet_wrap_string(janet_formatc("%s/%s", reg->name_prefix, reg->name)));
|
||||
} else {
|
||||
janet_table_put(t, janet_ckeywordv("name"), janet_cstringv(reg->name));
|
||||
}
|
||||
if (NULL != reg->source_file) {
|
||||
janet_table_put(t, janet_ckeywordv("source"), janet_cstringv(reg->source_file));
|
||||
}
|
||||
if (reg->source_line > 0) {
|
||||
janet_table_put(t, janet_ckeywordv("source-line"), janet_wrap_integer(reg->source_line));
|
||||
janet_table_put(t, janet_ckeywordv("source-column"), janet_wrap_integer(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
janet_table_put(t, janet_ckeywordv("c"), janet_wrap_true());
|
||||
@@ -252,26 +314,62 @@ static Janet doframe(JanetStackFrame *frame) {
|
||||
if (frame->func && frame->pc) {
|
||||
Janet *stack = (Janet *)frame + JANET_FRAME_SIZE;
|
||||
JanetArray *slots;
|
||||
off = (int32_t) (frame->pc - def->bytecode);
|
||||
janet_assert(def != NULL, "def != NULL");
|
||||
off = (int32_t)(frame->pc - def->bytecode);
|
||||
janet_table_put(t, janet_ckeywordv("pc"), janet_wrap_integer(off));
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
janet_table_put(t, janet_ckeywordv("source-start"), janet_wrap_integer(mapping.start));
|
||||
janet_table_put(t, janet_ckeywordv("source-end"), janet_wrap_integer(mapping.end));
|
||||
janet_table_put(t, janet_ckeywordv("source-line"), janet_wrap_integer(mapping.line));
|
||||
janet_table_put(t, janet_ckeywordv("source-column"), janet_wrap_integer(mapping.column));
|
||||
}
|
||||
if (def->source) {
|
||||
janet_table_put(t, janet_ckeywordv("source"), janet_wrap_string(def->source));
|
||||
}
|
||||
/* Add stack arguments */
|
||||
slots = janet_array(def->slotcount);
|
||||
memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
|
||||
safe_memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
|
||||
slots->count = def->slotcount;
|
||||
janet_table_put(t, janet_ckeywordv("slots"), janet_wrap_array(slots));
|
||||
/* Add local bindings */
|
||||
if (def->symbolmap) {
|
||||
JanetTable *local_bindings = janet_table(0);
|
||||
for (int32_t i = def->symbolmap_length - 1; i >= 0; i--) {
|
||||
JanetSymbolMap jsm = def->symbolmap[i];
|
||||
Janet value = janet_wrap_nil();
|
||||
uint32_t pc = (uint32_t)(frame->pc - def->bytecode);
|
||||
if (jsm.birth_pc == UINT32_MAX) {
|
||||
JanetFuncEnv *env = frame->func->envs[jsm.death_pc];
|
||||
if (env->offset > 0) {
|
||||
value = env->as.fiber->data[env->offset + jsm.slot_index];
|
||||
} else {
|
||||
value = env->as.values[jsm.slot_index];
|
||||
}
|
||||
} else if (pc >= jsm.birth_pc && pc < jsm.death_pc) {
|
||||
value = stack[jsm.slot_index];
|
||||
}
|
||||
janet_table_put(local_bindings, janet_wrap_symbol(jsm.symbol), value);
|
||||
}
|
||||
janet_table_put(t, janet_ckeywordv("locals"), janet_wrap_table(local_bindings));
|
||||
}
|
||||
}
|
||||
return janet_wrap_table(t);
|
||||
}
|
||||
|
||||
static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_stack,
|
||||
"(debug/stack fib)",
|
||||
"Gets information about the stack as an array of tables. Each table "
|
||||
"in the array contains information about a stack frame. The top-most, current "
|
||||
"stack frame is the first table in the array, and the bottom-most stack frame "
|
||||
"is the last value. Each stack frame contains some of the following attributes:\n\n"
|
||||
"* :c - true if the stack frame is a c function invocation\n\n"
|
||||
"* :source-column - the current source column of the stack frame\n\n"
|
||||
"* :function - the function that the stack frame represents\n\n"
|
||||
"* :source-line - the current source line of the stack frame\n\n"
|
||||
"* :name - the human-friendly name of the function\n\n"
|
||||
"* :pc - integer indicating the location of the program counter\n\n"
|
||||
"* :source - string with the file path or other identifier for the source code\n\n"
|
||||
"* :slots - array of all values in each slot\n\n"
|
||||
"* :tail - boolean indicating a tail call") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
JanetArray *array = janet_array(0);
|
||||
@@ -287,14 +385,24 @@ static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
JANET_CORE_FN(cfun_debug_stacktrace,
|
||||
"(debug/stacktrace fiber &opt err prefix)",
|
||||
"Prints a nice looking stacktrace for a fiber. Can optionally provide "
|
||||
"an error value to print the stack trace with. If `err` is nil or not "
|
||||
"provided, and no prefix is given, will skip the error line. Returns the fiber.") {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
janet_stacktrace(fiber, argv[1]);
|
||||
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
|
||||
const char *prefix = janet_optcstring(argv, argc, 2, NULL);
|
||||
janet_stacktrace_ext(fiber, x, prefix);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_debug_argstack,
|
||||
"(debug/arg-stack fiber)",
|
||||
"Gets all values currently on the fiber's argument stack. Normally, "
|
||||
"this should be empty unless the fiber signals while pushing arguments "
|
||||
"to make a function call. Returns a new array.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
JanetArray *array = janet_array(fiber->stacktop - fiber->stackstart);
|
||||
@@ -303,78 +411,31 @@ static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static const JanetReg debug_cfuns[] = {
|
||||
{
|
||||
"debug/break", cfun_debug_break,
|
||||
JDOC("(debug/break source byte-offset)\n\n"
|
||||
"Sets a breakpoint with source a key at a given byte offset. An offset "
|
||||
"of 0 is the first byte in a file. Will throw an error if the breakpoint location "
|
||||
"cannot be found. For example\n\n"
|
||||
"\t(debug/break \"core.janet\" 1000)\n\n"
|
||||
"wil set a breakpoint at the 1000th byte of the file core.janet.")
|
||||
},
|
||||
{
|
||||
"debug/unbreak", cfun_debug_unbreak,
|
||||
JDOC("(debug/unbreak source byte-offset)\n\n"
|
||||
"Remove a breakpoint with a source key at a given byte offset. An offset "
|
||||
"of 0 is the first byte in a file. Will throw an error if the breakpoint "
|
||||
"cannot be found.")
|
||||
},
|
||||
{
|
||||
"debug/fbreak", cfun_debug_fbreak,
|
||||
JDOC("(debug/fbreak fun [,pc=0])\n\n"
|
||||
"Set a breakpoint in a given function. pc is an optional offset, which "
|
||||
"is in bytecode instructions. fun is a function value. Will throw an error "
|
||||
"if the offset is too large or negative.")
|
||||
},
|
||||
{
|
||||
"debug/unfbreak", cfun_debug_unfbreak,
|
||||
JDOC("(debug/unfbreak fun [,pc=0])\n\n"
|
||||
"Unset a breakpoint set with debug/fbreak.")
|
||||
},
|
||||
{
|
||||
"debug/arg-stack", cfun_debug_argstack,
|
||||
JDOC("(debug/arg-stack fiber)\n\n"
|
||||
"Gets all values currently on the fiber's argument stack. Normally, "
|
||||
"this should be empty unless the fiber signals while pushing arguments "
|
||||
"to make a function call. Returns a new array.")
|
||||
},
|
||||
{
|
||||
"debug/stack", cfun_debug_stack,
|
||||
JDOC("(debug/stack fib)\n\n"
|
||||
"Gets information about the stack as an array of tables. Each table "
|
||||
"in the array contains information about a stack frame. The top most, current "
|
||||
"stack frame is the first table in the array, and the bottom most stack frame "
|
||||
"is the last value. Each stack frame contains some of the following attributes:\n\n"
|
||||
"\t:c - true if the stack frame is a c function invocation\n"
|
||||
"\t:column - the current source column of the stack frame\n"
|
||||
"\t:function - the function that the stack frame represents\n"
|
||||
"\t:line - the current source line of the stack frame\n"
|
||||
"\t:name - the human friendly name of the function\n"
|
||||
"\t:pc - integer indicating the location of the program counter\n"
|
||||
"\t:source - string with the file path or other identifier for the source code\n"
|
||||
"\t:slots - array of all values in each slot\n"
|
||||
"\t:tail - boolean indicating a tail call")
|
||||
},
|
||||
{
|
||||
"debug/stacktrace", cfun_debug_stacktrace,
|
||||
JDOC("(debug/stacktrace fiber err)\n\n"
|
||||
"Prints a nice looking stacktrace for a fiber. The error message "
|
||||
"err must be passed to the function as fiber's do not keep track of "
|
||||
"the last error they have thrown. Returns the fiber.")
|
||||
},
|
||||
{
|
||||
"debug/lineage", cfun_debug_lineage,
|
||||
JDOC("(debug/lineage fib)\n\n"
|
||||
"Returns an array of all child fibers from a root fiber. This function "
|
||||
"is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
|
||||
"the fiber handling the error can see which fiber raised the signal. This function should "
|
||||
"be used mostly for debugging purposes.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
JANET_CORE_FN(cfun_debug_step,
|
||||
"(debug/step fiber &opt x)",
|
||||
"Run a fiber for one virtual instruction of the Janet machine. Can optionally "
|
||||
"pass in a value that will be passed as the resuming value. Returns the signal value, "
|
||||
"which will usually be nil, as breakpoints raise nil signals.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
Janet out = janet_wrap_nil();
|
||||
janet_step(fiber, argc == 1 ? janet_wrap_nil() : argv[1], &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_debug(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, debug_cfuns);
|
||||
JanetRegExt debug_cfuns[] = {
|
||||
JANET_CORE_REG("debug/break", cfun_debug_break),
|
||||
JANET_CORE_REG("debug/unbreak", cfun_debug_unbreak),
|
||||
JANET_CORE_REG("debug/fbreak", cfun_debug_fbreak),
|
||||
JANET_CORE_REG("debug/unfbreak", cfun_debug_unfbreak),
|
||||
JANET_CORE_REG("debug/arg-stack", cfun_debug_argstack),
|
||||
JANET_CORE_REG("debug/stack", cfun_debug_stack),
|
||||
JANET_CORE_REG("debug/stacktrace", cfun_debug_stacktrace),
|
||||
JANET_CORE_REG("debug/lineage", cfun_debug_lineage),
|
||||
JANET_CORE_REG("debug/step", cfun_debug_step),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, debug_cfuns);
|
||||
}
|
||||
|
||||
114
src/core/emit.c
114
src/core/emit.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "emit.h"
|
||||
#include "vector.h"
|
||||
#include "regalloc.h"
|
||||
@@ -36,7 +37,7 @@ int32_t janetc_allocfar(JanetCompiler *c) {
|
||||
return reg;
|
||||
}
|
||||
|
||||
/* Get a register less than 256 */
|
||||
/* Get a register less than 256 for temporary use. */
|
||||
int32_t janetc_allocnear(JanetCompiler *c, JanetcRegisterTemp tag) {
|
||||
return janetc_regalloc_temp(&c->scope->ra, tag);
|
||||
}
|
||||
@@ -78,32 +79,31 @@ static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) {
|
||||
case JANET_NIL:
|
||||
janetc_emit(c, (reg << 8) | JOP_LOAD_NIL);
|
||||
break;
|
||||
case JANET_TRUE:
|
||||
janetc_emit(c, (reg << 8) | JOP_LOAD_TRUE);
|
||||
case JANET_BOOLEAN:
|
||||
janetc_emit(c, (reg << 8) |
|
||||
(janet_unwrap_boolean(k) ? JOP_LOAD_TRUE : JOP_LOAD_FALSE));
|
||||
break;
|
||||
case JANET_FALSE:
|
||||
janetc_emit(c, (reg << 8) | JOP_LOAD_FALSE);
|
||||
break;
|
||||
case JANET_NUMBER:
|
||||
{
|
||||
double dval = janet_unwrap_number(k);
|
||||
int32_t i = (int32_t) dval;
|
||||
if (dval != i || !(dval >= INT16_MIN && dval <= INT16_MAX))
|
||||
goto do_constant;
|
||||
janetc_emit(c,
|
||||
(i << 16) |
|
||||
case JANET_NUMBER: {
|
||||
double dval = janet_unwrap_number(k);
|
||||
if (dval < INT16_MIN || dval > INT16_MAX)
|
||||
goto do_constant;
|
||||
int32_t i = (int32_t) dval;
|
||||
if (dval != i)
|
||||
goto do_constant;
|
||||
uint32_t iu = (uint32_t)i;
|
||||
janetc_emit(c,
|
||||
(iu << 16) |
|
||||
(reg << 8) |
|
||||
JOP_LOAD_INTEGER);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
do_constant:
|
||||
{
|
||||
do_constant: {
|
||||
int32_t cindex = janetc_const(c, k);
|
||||
janetc_emit(c,
|
||||
(cindex << 16) |
|
||||
(reg << 8) |
|
||||
JOP_LOAD_CONSTANT);
|
||||
(cindex << 16) |
|
||||
(reg << 8) |
|
||||
JOP_LOAD_CONSTANT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -111,53 +111,53 @@ static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) {
|
||||
|
||||
/* Move a slot to a near register */
|
||||
static void janetc_movenear(JanetCompiler *c,
|
||||
int32_t dest,
|
||||
JanetSlot src) {
|
||||
int32_t dest,
|
||||
JanetSlot src) {
|
||||
if (src.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF)) {
|
||||
janetc_loadconst(c, src.constant, dest);
|
||||
/* If we also are a reference, deref the one element array */
|
||||
if (src.flags & JANET_SLOT_REF) {
|
||||
janetc_emit(c,
|
||||
(dest << 16) |
|
||||
(dest << 8) |
|
||||
JOP_GET_INDEX);
|
||||
(dest << 16) |
|
||||
(dest << 8) |
|
||||
JOP_GET_INDEX);
|
||||
}
|
||||
} else if (src.envindex >= 0) {
|
||||
janetc_emit(c,
|
||||
((uint32_t)(src.index) << 24) |
|
||||
((uint32_t)(src.envindex) << 16) |
|
||||
((uint32_t)(dest) << 8) |
|
||||
JOP_LOAD_UPVALUE);
|
||||
((uint32_t)(src.index) << 24) |
|
||||
((uint32_t)(src.envindex) << 16) |
|
||||
((uint32_t)(dest) << 8) |
|
||||
JOP_LOAD_UPVALUE);
|
||||
} else if (src.index > 0xFF || src.index != dest) {
|
||||
janetc_emit(c,
|
||||
((uint32_t)(src.index) << 16) |
|
||||
((uint32_t)(dest) << 8) |
|
||||
((uint32_t)(src.index) << 16) |
|
||||
((uint32_t)(dest) << 8) |
|
||||
JOP_MOVE_NEAR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move a near register to a Slot. */
|
||||
static void janetc_moveback(JanetCompiler *c,
|
||||
JanetSlot dest,
|
||||
int32_t src) {
|
||||
JanetSlot dest,
|
||||
int32_t src) {
|
||||
if (dest.flags & JANET_SLOT_REF) {
|
||||
int32_t refreg = janetc_regalloc_temp(&c->scope->ra, JANETC_REGTEMP_5);
|
||||
janetc_loadconst(c, dest.constant, refreg);
|
||||
janetc_emit(c,
|
||||
(src << 16) |
|
||||
(refreg << 8) |
|
||||
JOP_PUT_INDEX);
|
||||
(src << 16) |
|
||||
(refreg << 8) |
|
||||
JOP_PUT_INDEX);
|
||||
janetc_regalloc_freetemp(&c->scope->ra, refreg, JANETC_REGTEMP_5);
|
||||
} else if (dest.envindex >= 0) {
|
||||
janetc_emit(c,
|
||||
((uint32_t)(dest.index) << 24) |
|
||||
((uint32_t)(dest.envindex) << 16) |
|
||||
((uint32_t)(src) << 8) |
|
||||
JOP_SET_UPVALUE);
|
||||
((uint32_t)(dest.index) << 24) |
|
||||
((uint32_t)(dest.envindex) << 16) |
|
||||
((uint32_t)(src) << 8) |
|
||||
JOP_SET_UPVALUE);
|
||||
} else if (dest.index != src) {
|
||||
janetc_emit(c,
|
||||
((uint32_t)(dest.index) << 16) |
|
||||
((uint32_t)(src) << 8) |
|
||||
((uint32_t)(dest.index) << 16) |
|
||||
((uint32_t)(src) << 8) |
|
||||
JOP_MOVE_FAR);
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ static int32_t janetc_regnear(JanetCompiler *c, JanetSlot s, JanetcRegisterTemp
|
||||
}
|
||||
|
||||
/* Check if two slots are equal */
|
||||
static int janetc_sequal(JanetSlot lhs, JanetSlot rhs) {
|
||||
int janetc_sequal(JanetSlot lhs, JanetSlot rhs) {
|
||||
if ((lhs.flags & ~JANET_SLOTTYPE_ANY) == (rhs.flags & ~JANET_SLOTTYPE_ANY) &&
|
||||
lhs.index == rhs.index &&
|
||||
lhs.envindex == rhs.envindex) {
|
||||
@@ -221,9 +221,9 @@ static int janetc_sequal(JanetSlot lhs, JanetSlot rhs) {
|
||||
/* Move values from one slot to another. The destination must
|
||||
* be writeable (not a literal). */
|
||||
void janetc_copy(
|
||||
JanetCompiler *c,
|
||||
JanetSlot dest,
|
||||
JanetSlot src) {
|
||||
JanetCompiler *c,
|
||||
JanetSlot dest,
|
||||
JanetSlot src) {
|
||||
if (dest.flags & JANET_SLOT_CONSTANT) {
|
||||
janetc_cerror(c, "cannot write to constant");
|
||||
return;
|
||||
@@ -240,19 +240,19 @@ void janetc_copy(
|
||||
return;
|
||||
}
|
||||
/* Process: src -> near -> dest */
|
||||
int32_t near = janetc_allocnear(c, JANETC_REGTEMP_3);
|
||||
janetc_movenear(c, near, src);
|
||||
janetc_moveback(c, dest, near);
|
||||
int32_t nearreg = janetc_allocnear(c, JANETC_REGTEMP_3);
|
||||
janetc_movenear(c, nearreg, src);
|
||||
janetc_moveback(c, dest, nearreg);
|
||||
/* Cleanup */
|
||||
janetc_regalloc_freetemp(&c->scope->ra, near, JANETC_REGTEMP_3);
|
||||
|
||||
janetc_regalloc_freetemp(&c->scope->ra, nearreg, JANETC_REGTEMP_3);
|
||||
}
|
||||
|
||||
/* Instruction templated emitters */
|
||||
|
||||
static int32_t emit1s(JanetCompiler *c, uint8_t op, JanetSlot s, int32_t rest, int wr) {
|
||||
int32_t reg = janetc_regnear(c, s, JANETC_REGTEMP_0);
|
||||
int32_t label = janet_v_count(c->buffer);
|
||||
janetc_emit(c, op | (reg << 8) | (rest << 16));
|
||||
janetc_emit(c, op | (reg << 8) | ((uint32_t)rest << 16));
|
||||
if (wr)
|
||||
janetc_moveback(c, s, reg);
|
||||
janetc_free_regnear(c, s, reg, JANETC_REGTEMP_0);
|
||||
@@ -294,7 +294,7 @@ static int32_t emit2s(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2,
|
||||
int32_t reg1 = janetc_regnear(c, s1, JANETC_REGTEMP_0);
|
||||
int32_t reg2 = janetc_regnear(c, s2, JANETC_REGTEMP_1);
|
||||
int32_t label = janet_v_count(c->buffer);
|
||||
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (rest << 24));
|
||||
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | ((uint32_t)rest << 24));
|
||||
janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1);
|
||||
if (wr)
|
||||
janetc_moveback(c, s1, reg1);
|
||||
@@ -327,7 +327,7 @@ int32_t janetc_emit_sss(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2
|
||||
int32_t reg2 = janetc_regnear(c, s2, JANETC_REGTEMP_1);
|
||||
int32_t reg3 = janetc_regnear(c, s3, JANETC_REGTEMP_2);
|
||||
int32_t label = janet_v_count(c->buffer);
|
||||
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (reg3 << 24));
|
||||
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | ((uint32_t)reg3 << 24));
|
||||
janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1);
|
||||
janetc_free_regnear(c, s3, reg3, JANETC_REGTEMP_2);
|
||||
if (wr)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -42,6 +42,9 @@ int32_t janetc_emit_ssi(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2
|
||||
int32_t janetc_emit_ssu(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2, uint8_t immediate, int wr);
|
||||
int32_t janetc_emit_sss(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2, JanetSlot s3, int wr);
|
||||
|
||||
/* Check if two slots are equivalent */
|
||||
int janetc_sequal(JanetSlot x, JanetSlot y);
|
||||
|
||||
/* Move value from one slot to another. Cannot copy to constant slots. */
|
||||
void janetc_copy(JanetCompiler *c, JanetSlot dest, JanetSlot src);
|
||||
|
||||
|
||||
3311
src/core/ev.c
Normal file
3311
src/core/ev.c
Normal file
File diff suppressed because it is too large
Load Diff
79
src/core/features.h
Normal file
79
src/core/features.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Feature test macros */
|
||||
|
||||
#ifndef JANET_FEATURES_H_defined
|
||||
#define JANET_FEATURES_H_defined
|
||||
|
||||
#if defined(__NetBSD__) || defined(__APPLE__) || defined(__OpenBSD__) \
|
||||
|| defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
/* Use BSD source on any BSD systems, include OSX */
|
||||
# define _BSD_SOURCE
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
#else
|
||||
/* Use POSIX feature flags */
|
||||
# ifndef _POSIX_C_SOURCE
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define _DARWIN_C_SOURCE
|
||||
#endif
|
||||
|
||||
/* Needed for sched.h for cpu count */
|
||||
#ifdef __linux__
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* needed for inet_pton and InitializeSRWLock */
|
||||
#ifdef __MINGW32__
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
|
||||
/* Needed for realpath on linux, as well as pthread rwlocks. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
#if _XOPEN_SOURCE < 600
|
||||
#undef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
/* Needed for timegm and other extensions when building with -std=c99.
|
||||
* It also defines realpath, etc, which would normally require
|
||||
* _XOPEN_SOURCE >= 500. */
|
||||
#if !defined(_NETBSD_SOURCE) && defined(__NetBSD__)
|
||||
#define _NETBSD_SOURCE
|
||||
#endif
|
||||
|
||||
/* Needed for several things when building with -std=c99. */
|
||||
#if !__BSD_VISIBLE && (defined(__DragonFly__) || defined(__FreeBSD__))
|
||||
#define __BSD_VISIBLE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1593
src/core/ffi.c
Normal file
1593
src/core/ffi.c
Normal file
File diff suppressed because it is too large
Load Diff
456
src/core/fiber.c
456
src/core/fiber.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "fiber.h"
|
||||
#include "state.h"
|
||||
#include "gc.h"
|
||||
@@ -34,7 +35,14 @@ static void fiber_reset(JanetFiber *fiber) {
|
||||
fiber->stackstart = JANET_FRAME_SIZE;
|
||||
fiber->stacktop = JANET_FRAME_SIZE;
|
||||
fiber->child = NULL;
|
||||
fiber->flags = JANET_FIBER_MASK_YIELD;
|
||||
fiber->flags = JANET_FIBER_MASK_YIELD | JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
||||
fiber->env = NULL;
|
||||
fiber->last_value = janet_wrap_nil();
|
||||
#ifdef JANET_EV
|
||||
fiber->waiting = NULL;
|
||||
fiber->sched_id = 0;
|
||||
fiber->supervisor_channel = NULL;
|
||||
#endif
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
|
||||
}
|
||||
|
||||
@@ -45,10 +53,11 @@ static JanetFiber *fiber_alloc(int32_t capacity) {
|
||||
capacity = 32;
|
||||
}
|
||||
fiber->capacity = capacity;
|
||||
data = malloc(sizeof(Janet) * capacity);
|
||||
data = janet_malloc(sizeof(Janet) * (size_t) capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm.next_collection += sizeof(Janet) * capacity;
|
||||
fiber->data = data;
|
||||
return fiber;
|
||||
}
|
||||
@@ -62,11 +71,23 @@ JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee, int32_t
|
||||
if (newstacktop >= fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * newstacktop);
|
||||
}
|
||||
memcpy(fiber->data + fiber->stacktop, argv, argc * sizeof(Janet));
|
||||
if (argv) {
|
||||
memcpy(fiber->data + fiber->stacktop, argv, argc * sizeof(Janet));
|
||||
} else {
|
||||
/* If argv not given, fill with nil */
|
||||
for (int32_t i = 0; i < argc; i++) {
|
||||
fiber->data[fiber->stacktop + i] = janet_wrap_nil();
|
||||
}
|
||||
}
|
||||
fiber->stacktop = newstacktop;
|
||||
}
|
||||
/* Don't panic on failure since we use this to implement janet_pcall */
|
||||
if (janet_fiber_funcframe(fiber, callee)) return NULL;
|
||||
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
|
||||
#ifdef JANET_EV
|
||||
fiber->waiting = NULL;
|
||||
fiber->supervisor_channel = NULL;
|
||||
#endif
|
||||
return fiber;
|
||||
}
|
||||
|
||||
@@ -75,29 +96,56 @@ JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, c
|
||||
return janet_fiber_reset(fiber_alloc(capacity), callee, argc, argv);
|
||||
}
|
||||
|
||||
#ifdef JANET_DEBUG
|
||||
/* Test for memory issues by reallocating fiber every time we push a stack frame */
|
||||
static void janet_fiber_refresh_memory(JanetFiber *fiber) {
|
||||
int32_t n = fiber->capacity;
|
||||
if (n) {
|
||||
Janet *newData = janet_malloc(sizeof(Janet) * n);
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(newData, fiber->data, fiber->capacity * sizeof(Janet));
|
||||
janet_free(fiber->data);
|
||||
fiber->data = newData;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Ensure that the fiber has enough extra capacity */
|
||||
void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
|
||||
Janet *newData = realloc(fiber->data, sizeof(Janet) * n);
|
||||
int32_t old_size = fiber->capacity;
|
||||
int32_t diff = n - old_size;
|
||||
Janet *newData = janet_realloc(fiber->data, sizeof(Janet) * n);
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
fiber->data = newData;
|
||||
fiber->capacity = n;
|
||||
janet_vm.next_collection += sizeof(Janet) * diff;
|
||||
}
|
||||
|
||||
/* Grow fiber if needed */
|
||||
static void janet_fiber_grow(JanetFiber *fiber, int32_t needed) {
|
||||
int32_t cap = needed > (INT32_MAX / 2) ? INT32_MAX : 2 * needed;
|
||||
janet_fiber_setcapacity(fiber, cap);
|
||||
}
|
||||
|
||||
/* Push a value on the next stack frame */
|
||||
void janet_fiber_push(JanetFiber *fiber, Janet x) {
|
||||
if (fiber->stacktop == INT32_MAX) janet_panic("stack overflow");
|
||||
if (fiber->stacktop >= fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * fiber->stacktop);
|
||||
janet_fiber_grow(fiber, fiber->stacktop);
|
||||
}
|
||||
fiber->data[fiber->stacktop++] = x;
|
||||
}
|
||||
|
||||
/* Push 2 values on the next stack frame */
|
||||
void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
|
||||
if (fiber->stacktop >= INT32_MAX - 1) janet_panic("stack overflow");
|
||||
int32_t newtop = fiber->stacktop + 2;
|
||||
if (newtop > fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * newtop);
|
||||
janet_fiber_grow(fiber, newtop);
|
||||
}
|
||||
fiber->data[fiber->stacktop] = x;
|
||||
fiber->data[fiber->stacktop + 1] = y;
|
||||
@@ -106,9 +154,10 @@ void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
|
||||
|
||||
/* Push 3 values on the next stack frame */
|
||||
void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
|
||||
if (fiber->stacktop >= INT32_MAX - 2) janet_panic("stack overflow");
|
||||
int32_t newtop = fiber->stacktop + 3;
|
||||
if (newtop > fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * newtop);
|
||||
janet_fiber_grow(fiber, newtop);
|
||||
}
|
||||
fiber->data[fiber->stacktop] = x;
|
||||
fiber->data[fiber->stacktop + 1] = y;
|
||||
@@ -118,14 +167,25 @@ void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
|
||||
|
||||
/* Push an array on the next stack frame */
|
||||
void janet_fiber_pushn(JanetFiber *fiber, const Janet *arr, int32_t n) {
|
||||
if (fiber->stacktop > INT32_MAX - n) janet_panic("stack overflow");
|
||||
int32_t newtop = fiber->stacktop + n;
|
||||
if (newtop > fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * newtop);
|
||||
janet_fiber_grow(fiber, newtop);
|
||||
}
|
||||
memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet));
|
||||
safe_memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet));
|
||||
fiber->stacktop = newtop;
|
||||
}
|
||||
|
||||
/* Create a struct with n values. If n is odd, the last value is ignored. */
|
||||
static Janet make_struct_n(const Janet *args, int32_t n) {
|
||||
int32_t i = 0;
|
||||
JanetKV *st = janet_struct_begin(n & (~1));
|
||||
for (; i < n; i += 2) {
|
||||
janet_struct_put(st, args[i], args[i + 1]);
|
||||
}
|
||||
return janet_wrap_struct(janet_struct_end(st));
|
||||
}
|
||||
|
||||
/* Push a stack frame to a fiber */
|
||||
int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
JanetStackFrame *newframe;
|
||||
@@ -138,14 +198,15 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
int32_t next_arity = fiber->stacktop - fiber->stackstart;
|
||||
|
||||
/* Check strict arity before messing with state */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
||||
if (func->def->arity != next_arity) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (next_arity < func->def->min_arity) return 1;
|
||||
if (next_arity > func->def->max_arity) return 1;
|
||||
|
||||
if (fiber->capacity < nextstacktop) {
|
||||
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
|
||||
#ifdef JANET_DEBUG
|
||||
} else {
|
||||
janet_fiber_refresh_memory(fiber);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Nil unset stack arguments (Needed for gc correctness) */
|
||||
@@ -166,12 +227,19 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
/* Check varargs */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
|
||||
int32_t tuplehead = fiber->frame + func->def->arity;
|
||||
int st = func->def->flags & JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
if (tuplehead >= oldtop) {
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(NULL, 0)
|
||||
: janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
} else {
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead));
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead)
|
||||
: janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,17 +252,79 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
static void janet_env_detach(JanetFuncEnv *env) {
|
||||
/* Check for closure environment */
|
||||
if (env) {
|
||||
size_t s = sizeof(Janet) * env->length;
|
||||
Janet *vmem = malloc(s);
|
||||
janet_env_valid(env);
|
||||
int32_t len = env->length;
|
||||
size_t s = sizeof(Janet) * (size_t) len;
|
||||
Janet *vmem = janet_malloc(s);
|
||||
janet_vm.next_collection += (uint32_t) s;
|
||||
if (NULL == vmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(vmem, env->as.fiber->data + env->offset, s);
|
||||
Janet *values = env->as.fiber->data + env->offset;
|
||||
safe_memcpy(vmem, values, s);
|
||||
uint32_t *bitset = janet_stack_frame(values)->func->def->closure_bitset;
|
||||
if (bitset) {
|
||||
/* Clear unneeded references in closure environment */
|
||||
for (int32_t i = 0; i < len; i += 32) {
|
||||
uint32_t mask = ~(bitset[i >> 5]);
|
||||
int32_t maxj = i + 32 > len ? len : i + 32;
|
||||
for (int32_t j = i; j < maxj; j++) {
|
||||
if (mask & 1) vmem[j] = janet_wrap_nil();
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
env->offset = 0;
|
||||
env->as.values = vmem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate potentially untrusted func env (unmarshalled envs are difficult to verify) */
|
||||
int janet_env_valid(JanetFuncEnv *env) {
|
||||
if (env->offset < 0) {
|
||||
int32_t real_offset = -(env->offset);
|
||||
JanetFiber *fiber = env->as.fiber;
|
||||
int32_t i = fiber->frame;
|
||||
while (i > 0) {
|
||||
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
if (real_offset == i &&
|
||||
frame->env == env &&
|
||||
frame->func &&
|
||||
frame->func->def->slotcount == env->length) {
|
||||
env->offset = real_offset;
|
||||
return 1;
|
||||
}
|
||||
i = frame->prevframe;
|
||||
}
|
||||
/* Invalid, set to empty off-stack variant. */
|
||||
env->offset = 0;
|
||||
env->length = 0;
|
||||
env->as.values = NULL;
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Detach a fiber from the env if the target fiber has stopped mutating */
|
||||
void janet_env_maybe_detach(JanetFuncEnv *env) {
|
||||
/* Check for detachable closure envs */
|
||||
janet_env_valid(env);
|
||||
if (env->offset > 0) {
|
||||
JanetFiberStatus s = janet_fiber_status(env->as.fiber);
|
||||
int isFinished = s == JANET_STATUS_DEAD ||
|
||||
s == JANET_STATUS_ERROR ||
|
||||
s == JANET_STATUS_USER0 ||
|
||||
s == JANET_STATUS_USER1 ||
|
||||
s == JANET_STATUS_USER2 ||
|
||||
s == JANET_STATUS_USER3 ||
|
||||
s == JANET_STATUS_USER4;
|
||||
if (isFinished) {
|
||||
janet_env_detach(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a tail frame for a function */
|
||||
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
int32_t i;
|
||||
@@ -204,14 +334,15 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
int32_t stacksize;
|
||||
|
||||
/* Check strict arity before messing with state */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
||||
if (func->def->arity != next_arity) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (next_arity < func->def->min_arity) return 1;
|
||||
if (next_arity > func->def->max_arity) return 1;
|
||||
|
||||
if (fiber->capacity < nextstacktop) {
|
||||
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
|
||||
#ifdef JANET_DEBUG
|
||||
} else {
|
||||
janet_fiber_refresh_memory(fiber);
|
||||
#endif
|
||||
}
|
||||
|
||||
Janet *stack = fiber->data + fiber->frame;
|
||||
@@ -225,14 +356,21 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
/* Check varargs */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
|
||||
int32_t tuplehead = fiber->stackstart + func->def->arity;
|
||||
int st = func->def->flags & JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
if (tuplehead >= fiber->stacktop) {
|
||||
if (tuplehead >= fiber->capacity) janet_fiber_setcapacity(fiber, 2 * (tuplehead + 1));
|
||||
for (i = fiber->stacktop; i < tuplehead; ++i) fiber->data[i] = janet_wrap_nil();
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(NULL, 0)
|
||||
: janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
||||
} else {
|
||||
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
fiber->stacktop - tuplehead));
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(
|
||||
fiber->data + tuplehead,
|
||||
fiber->stacktop - tuplehead)
|
||||
: janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
fiber->stacktop - tuplehead));
|
||||
}
|
||||
stacksize = tuplehead - fiber->stackstart + 1;
|
||||
} else {
|
||||
@@ -267,6 +405,10 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) {
|
||||
|
||||
if (fiber->capacity < nextstacktop) {
|
||||
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
|
||||
#ifdef JANET_DEBUG
|
||||
} else {
|
||||
janet_fiber_refresh_memory(fiber);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the next frame */
|
||||
@@ -282,8 +424,7 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) {
|
||||
newframe->flags = 0;
|
||||
}
|
||||
|
||||
/* Pop a stack frame from the fiber. Returns the new stack frame, or
|
||||
* NULL if there are no more frames */
|
||||
/* Pop a stack frame from the fiber. */
|
||||
void janet_fiber_popframe(JanetFiber *fiber) {
|
||||
JanetStackFrame *frame = janet_fiber_frame(fiber);
|
||||
if (fiber->frame == 0) return;
|
||||
@@ -297,22 +438,86 @@ void janet_fiber_popframe(JanetFiber *fiber) {
|
||||
fiber->frame = frame->prevframe;
|
||||
}
|
||||
|
||||
JanetFiberStatus janet_fiber_status(JanetFiber *f) {
|
||||
return ((f)->flags & JANET_FIBER_STATUS_MASK) >> JANET_FIBER_STATUS_OFFSET;
|
||||
}
|
||||
|
||||
JanetFiber *janet_current_fiber(void) {
|
||||
return janet_vm.fiber;
|
||||
}
|
||||
|
||||
JanetFiber *janet_root_fiber(void) {
|
||||
return janet_vm.root_fiber;
|
||||
}
|
||||
|
||||
/* CFuns */
|
||||
|
||||
static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JANET_CORE_FN(cfun_fiber_getenv,
|
||||
"(fiber/getenv fiber)",
|
||||
"Gets the environment for a fiber. Returns nil if no such table is "
|
||||
"set yet.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return fiber->env ?
|
||||
janet_wrap_table(fiber->env) :
|
||||
janet_wrap_nil();
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_fiber_setenv,
|
||||
"(fiber/setenv fiber table)",
|
||||
"Sets the environment table for a fiber. Set to nil to remove the current "
|
||||
"environment.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
if (janet_checktype(argv[1], JANET_NIL)) {
|
||||
fiber->env = NULL;
|
||||
} else {
|
||||
fiber->env = janet_gettable(argv, 1);
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_fiber_new,
|
||||
"(fiber/new func &opt sigmask env)",
|
||||
"Create a new fiber with function body func. Can optionally "
|
||||
"take a set of signals `sigmask` to capture from child fibers, "
|
||||
"and an environment table `env`. The mask is specified as a keyword where each character "
|
||||
"is used to indicate a signal to block. If the ev module is enabled, and "
|
||||
"this fiber is used as an argument to `ev/go`, these \"blocked\" signals "
|
||||
"will result in messages being sent to the supervisor channel. "
|
||||
"The default sigmask is :y. "
|
||||
"For example,\n\n"
|
||||
" (fiber/new myfun :e123)\n\n"
|
||||
"blocks error signals and user signals 1, 2 and 3. The signals are "
|
||||
"as follows:\n\n"
|
||||
"* :a - block all signals\n"
|
||||
"* :d - block debug signals\n"
|
||||
"* :e - block error signals\n"
|
||||
"* :t - block termination signals: error + user[0-4]\n"
|
||||
"* :u - block user signals\n"
|
||||
"* :y - block yield signals\n"
|
||||
"* :w - block await signals (user9)\n"
|
||||
"* :r - block interrupt signals (user8)\n"
|
||||
"* :0-9 - block a specific user signal\n\n"
|
||||
"The sigmask argument also can take environment flags. If any mutually "
|
||||
"exclusive flags are present, the last flag takes precedence.\n\n"
|
||||
"* :i - inherit the environment from the current fiber\n"
|
||||
"* :p - the environment table's prototype is the current environment table") {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetFunction *func = janet_getfunction(argv, 0);
|
||||
JanetFiber *fiber;
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
||||
if (func->def->arity != 0) {
|
||||
janet_panic("expected nullary function in fiber constructor");
|
||||
}
|
||||
if (func->def->min_arity > 1) {
|
||||
janet_panicf("fiber function must accept 0 or 1 arguments");
|
||||
}
|
||||
fiber = janet_fiber(func, 64, 0, NULL);
|
||||
if (argc == 2) {
|
||||
fiber = janet_fiber(func, 64, func->def->min_arity, NULL);
|
||||
janet_assert(fiber != NULL, "bad fiber arity check");
|
||||
if (argc == 3 && !janet_checktype(argv[2], JANET_NIL)) {
|
||||
fiber->env = janet_gettable(argv, 2);
|
||||
}
|
||||
if (argc >= 2) {
|
||||
int32_t i;
|
||||
JanetByteView view = janet_getbytes(argv, 1);
|
||||
fiber->flags = 0;
|
||||
fiber->flags = JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
|
||||
for (i = 0; i < view.len; i++) {
|
||||
if (view.bytes[i] >= '0' && view.bytes[i] <= '9') {
|
||||
@@ -320,7 +525,7 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
} else {
|
||||
switch (view.bytes[i]) {
|
||||
default:
|
||||
janet_panicf("invalid flag %c, expected a, d, e, u, or y", view.bytes[i]);
|
||||
janet_panicf("invalid flag %c, expected a, t, d, e, u, y, w, r, i, or p", view.bytes[i]);
|
||||
break;
|
||||
case 'a':
|
||||
fiber->flags |=
|
||||
@@ -329,6 +534,15 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
JANET_FIBER_MASK_USER |
|
||||
JANET_FIBER_MASK_YIELD;
|
||||
break;
|
||||
case 't':
|
||||
fiber->flags |=
|
||||
JANET_FIBER_MASK_ERROR |
|
||||
JANET_FIBER_MASK_USER0 |
|
||||
JANET_FIBER_MASK_USER1 |
|
||||
JANET_FIBER_MASK_USER2 |
|
||||
JANET_FIBER_MASK_USER3 |
|
||||
JANET_FIBER_MASK_USER4;
|
||||
break;
|
||||
case 'd':
|
||||
fiber->flags |= JANET_FIBER_MASK_DEBUG;
|
||||
break;
|
||||
@@ -341,6 +555,25 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
case 'y':
|
||||
fiber->flags |= JANET_FIBER_MASK_YIELD;
|
||||
break;
|
||||
case 'w':
|
||||
fiber->flags |= JANET_FIBER_MASK_USER9;
|
||||
break;
|
||||
case 'r':
|
||||
fiber->flags |= JANET_FIBER_MASK_USER8;
|
||||
break;
|
||||
case 'i':
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(0);
|
||||
}
|
||||
fiber->env = janet_vm.fiber->env;
|
||||
break;
|
||||
case 'p':
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(0);
|
||||
}
|
||||
fiber->env = janet_table(0);
|
||||
fiber->env->proto = janet_vm.fiber->env;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,27 +581,55 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_fiber(fiber);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_status(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_fiber_status,
|
||||
"(fiber/status fib)",
|
||||
"Get the status of a fiber. The status will be one of:\n\n"
|
||||
"* :dead - the fiber has finished\n"
|
||||
"* :error - the fiber has errored out\n"
|
||||
"* :debug - the fiber is suspended in debug mode\n"
|
||||
"* :pending - the fiber has been yielded\n"
|
||||
"* :user(0-7) - the fiber is suspended by a user signal\n"
|
||||
"* :interrupted - the fiber was interrupted\n"
|
||||
"* :suspended - the fiber is waiting to be resumed by the scheduler\n"
|
||||
"* :alive - the fiber is currently running and cannot be resumed\n"
|
||||
"* :new - the fiber has just been created and not yet run") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
|
||||
JANET_FIBER_STATUS_OFFSET;
|
||||
uint32_t s = janet_fiber_status(fiber);
|
||||
return janet_ckeywordv(janet_status_names[s]);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_current(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_fiber_current,
|
||||
"(fiber/current)",
|
||||
"Returns the currently running fiber.") {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_fiber(janet_vm_fiber);
|
||||
return janet_wrap_fiber(janet_vm.fiber);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_maxstack(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_fiber_root,
|
||||
"(fiber/root)",
|
||||
"Returns the current root fiber. The root fiber is the oldest ancestor "
|
||||
"that does not have a parent.") {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_fiber(janet_vm.root_fiber);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_fiber_maxstack,
|
||||
"(fiber/maxstack fib)",
|
||||
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
|
||||
"the fiber's stack is not allocated up front, the fiber will not allocated more "
|
||||
"than this amount and will throw a stack-overflow error if more memory is needed. ") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return janet_wrap_integer(fiber->maxstack);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_setmaxstack(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_fiber_setmaxstack,
|
||||
"(fiber/setmaxstack fib maxstack)",
|
||||
"Sets the maximum stack size in janet values for a fiber. By default, the "
|
||||
"maximum stack size is usually 8192.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
int32_t maxs = janet_getinteger(argv, 1);
|
||||
@@ -379,59 +640,48 @@ static Janet cfun_fiber_setmaxstack(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg fiber_cfuns[] = {
|
||||
{
|
||||
"fiber/new", cfun_fiber_new,
|
||||
JDOC("(fiber/new func [,sigmask])\n\n"
|
||||
"Create a new fiber with function body func. Can optionally "
|
||||
"take a set of signals to block from the current parent fiber "
|
||||
"when called. The mask is specified as a keyword where each character "
|
||||
"is used to indicate a signal to block. The default sigmask is :y. "
|
||||
"For example, \n\n"
|
||||
"\t(fiber/new myfun :e123)\n\n"
|
||||
"blocks error signals and user signals 1, 2 and 3. The signals are "
|
||||
"as follows: \n\n"
|
||||
"\ta - block all signals\n"
|
||||
"\td - block debug signals\n"
|
||||
"\te - block error signals\n"
|
||||
"\tu - block user signals\n"
|
||||
"\ty - block yield signals\n"
|
||||
"\t0-9 - block a specific user signal")
|
||||
},
|
||||
{
|
||||
"fiber/status", cfun_fiber_status,
|
||||
JDOC("(fiber/status fib)\n\n"
|
||||
"Get the status of a fiber. The status will be one of:\n\n"
|
||||
"\t:dead - the fiber has finished\n"
|
||||
"\t:error - the fiber has errored out\n"
|
||||
"\t:debug - the fiber is suspended in debug mode\n"
|
||||
"\t:pending - the fiber has been yielded\n"
|
||||
"\t:user(0-9) - the fiber is suspended by a user signal\n"
|
||||
"\t:alive - the fiber is currently running and cannot be resumed\n"
|
||||
"\t:new - the fiber has just been created and not yet run")
|
||||
},
|
||||
{
|
||||
"fiber/current", cfun_fiber_current,
|
||||
JDOC("(fiber/current)\n\n"
|
||||
"Returns the currently running fiber.")
|
||||
},
|
||||
{
|
||||
"fiber/maxstack", cfun_fiber_maxstack,
|
||||
JDOC("(fiber/maxstack fib)\n\n"
|
||||
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
|
||||
"the fiber's stack is not allocated up front, the fiber will not allocated more "
|
||||
"than this amount and will throw a stack-overflow error if more memory is needed. ")
|
||||
},
|
||||
{
|
||||
"fiber/setmaxstack", cfun_fiber_setmaxstack,
|
||||
JDOC("(fiber/setmaxstack fib maxstack)\n\n"
|
||||
"Sets the maximum stack size in janet values for a fiber. By default, the "
|
||||
"maximum stack size is usually 8192.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
int janet_fiber_can_resume(JanetFiber *fiber) {
|
||||
JanetFiberStatus s = janet_fiber_status(fiber);
|
||||
int isFinished = s == JANET_STATUS_DEAD ||
|
||||
s == JANET_STATUS_ERROR ||
|
||||
s == JANET_STATUS_USER0 ||
|
||||
s == JANET_STATUS_USER1 ||
|
||||
s == JANET_STATUS_USER2 ||
|
||||
s == JANET_STATUS_USER3 ||
|
||||
s == JANET_STATUS_USER4;
|
||||
return !isFinished;
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_fiber_can_resume,
|
||||
"(fiber/can-resume? fiber)",
|
||||
"Check if a fiber is finished and cannot be resumed.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return janet_wrap_boolean(janet_fiber_can_resume(fiber));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_fiber_last_value,
|
||||
"(fiber/last-value)",
|
||||
"Get the last value returned or signaled from the fiber.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return fiber->last_value;
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_fiber(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, fiber_cfuns);
|
||||
JanetRegExt fiber_cfuns[] = {
|
||||
JANET_CORE_REG("fiber/new", cfun_fiber_new),
|
||||
JANET_CORE_REG("fiber/status", cfun_fiber_status),
|
||||
JANET_CORE_REG("fiber/root", cfun_fiber_root),
|
||||
JANET_CORE_REG("fiber/current", cfun_fiber_current),
|
||||
JANET_CORE_REG("fiber/maxstack", cfun_fiber_maxstack),
|
||||
JANET_CORE_REG("fiber/setmaxstack", cfun_fiber_setmaxstack),
|
||||
JANET_CORE_REG("fiber/getenv", cfun_fiber_getenv),
|
||||
JANET_CORE_REG("fiber/setenv", cfun_fiber_setenv),
|
||||
JANET_CORE_REG("fiber/can-resume?", cfun_fiber_can_resume),
|
||||
JANET_CORE_REG("fiber/last-value", cfun_fiber_last_value),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, fiber_cfuns);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -24,10 +24,41 @@
|
||||
#define JANET_FIBER_H_defined
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#endif
|
||||
|
||||
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
|
||||
/* Fiber signal masks. */
|
||||
#define JANET_FIBER_MASK_ERROR 2
|
||||
#define JANET_FIBER_MASK_DEBUG 4
|
||||
#define JANET_FIBER_MASK_YIELD 8
|
||||
|
||||
#define JANET_FIBER_MASK_USER0 (16 << 0)
|
||||
#define JANET_FIBER_MASK_USER1 (16 << 1)
|
||||
#define JANET_FIBER_MASK_USER2 (16 << 2)
|
||||
#define JANET_FIBER_MASK_USER3 (16 << 3)
|
||||
#define JANET_FIBER_MASK_USER4 (16 << 4)
|
||||
#define JANET_FIBER_MASK_USER5 (16 << 5)
|
||||
#define JANET_FIBER_MASK_USER6 (16 << 6)
|
||||
#define JANET_FIBER_MASK_USER7 (16 << 7)
|
||||
#define JANET_FIBER_MASK_USER8 (16 << 8)
|
||||
#define JANET_FIBER_MASK_USER9 (16 << 9)
|
||||
|
||||
#define JANET_FIBER_MASK_USERN(N) (16 << (N))
|
||||
#define JANET_FIBER_MASK_USER 0x3FF0
|
||||
|
||||
#define JANET_FIBER_STATUS_MASK 0x3F0000
|
||||
#define JANET_FIBER_RESUME_SIGNAL 0x400000
|
||||
#define JANET_FIBER_STATUS_OFFSET 16
|
||||
|
||||
#define JANET_FIBER_BREAKPOINT 0x1000000
|
||||
#define JANET_FIBER_RESUME_NO_USEVAL 0x2000000
|
||||
#define JANET_FIBER_RESUME_NO_SKIP 0x4000000
|
||||
#define JANET_FIBER_DID_LONGJUMP 0x8000000
|
||||
#define JANET_FIBER_FLAG_MASK 0xF000000
|
||||
|
||||
#define JANET_FIBER_EV_FLAG_CANCELED 0x10000
|
||||
#define JANET_FIBER_EV_FLAG_SUSPENDED 0x20000
|
||||
#define JANET_FIBER_FLAG_ROOT 0x40000
|
||||
|
||||
#define janet_fiber_set_status(f, s) do {\
|
||||
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\
|
||||
@@ -45,5 +76,11 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func);
|
||||
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func);
|
||||
void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun);
|
||||
void janet_fiber_popframe(JanetFiber *fiber);
|
||||
void janet_env_maybe_detach(JanetFuncEnv *env);
|
||||
int janet_env_valid(JanetFuncEnv *env);
|
||||
|
||||
#ifdef JANET_EV
|
||||
void janet_fiber_did_resume(JanetFiber *fiber);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
448
src/core/gc.c
448
src/core/gc.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -21,23 +21,16 @@
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#include "symcache.h"
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include "fiber.h"
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
/* GC State */
|
||||
JANET_THREAD_LOCAL void *janet_vm_blocks;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_gc_interval;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_next_collection;
|
||||
JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0;
|
||||
|
||||
/* Roots */
|
||||
JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
|
||||
|
||||
/* Helpers for marking the various gc types */
|
||||
static void janet_mark_funcenv(JanetFuncEnv *env);
|
||||
static void janet_mark_funcdef(JanetFuncDef *def);
|
||||
@@ -51,27 +44,51 @@ static void janet_mark_string(const uint8_t *str);
|
||||
static void janet_mark_fiber(JanetFiber *fiber);
|
||||
static void janet_mark_abstract(void *adata);
|
||||
|
||||
/* Local state that is only temporary */
|
||||
/* Local state that is only temporary for gc */
|
||||
static JANET_THREAD_LOCAL uint32_t depth = JANET_RECURSION_GUARD;
|
||||
static JANET_THREAD_LOCAL uint32_t orig_rootcount;
|
||||
static JANET_THREAD_LOCAL size_t orig_rootcount;
|
||||
|
||||
/* Hint to the GC that we may need to collect */
|
||||
void janet_gcpressure(size_t s) {
|
||||
janet_vm.next_collection += s;
|
||||
}
|
||||
|
||||
/* Mark a value */
|
||||
void janet_mark(Janet x) {
|
||||
if (depth) {
|
||||
depth--;
|
||||
switch (janet_type(x)) {
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
case JANET_STRING:
|
||||
case JANET_KEYWORD:
|
||||
case JANET_SYMBOL: janet_mark_string(janet_unwrap_string(x)); break;
|
||||
case JANET_FUNCTION: janet_mark_function(janet_unwrap_function(x)); break;
|
||||
case JANET_ARRAY: janet_mark_array(janet_unwrap_array(x)); break;
|
||||
case JANET_TABLE: janet_mark_table(janet_unwrap_table(x)); break;
|
||||
case JANET_STRUCT: janet_mark_struct(janet_unwrap_struct(x)); break;
|
||||
case JANET_TUPLE: janet_mark_tuple(janet_unwrap_tuple(x)); break;
|
||||
case JANET_BUFFER: janet_mark_buffer(janet_unwrap_buffer(x)); break;
|
||||
case JANET_FIBER: janet_mark_fiber(janet_unwrap_fiber(x)); break;
|
||||
case JANET_ABSTRACT: janet_mark_abstract(janet_unwrap_abstract(x)); break;
|
||||
case JANET_SYMBOL:
|
||||
janet_mark_string(janet_unwrap_string(x));
|
||||
break;
|
||||
case JANET_FUNCTION:
|
||||
janet_mark_function(janet_unwrap_function(x));
|
||||
break;
|
||||
case JANET_ARRAY:
|
||||
janet_mark_array(janet_unwrap_array(x));
|
||||
break;
|
||||
case JANET_TABLE:
|
||||
janet_mark_table(janet_unwrap_table(x));
|
||||
break;
|
||||
case JANET_STRUCT:
|
||||
janet_mark_struct(janet_unwrap_struct(x));
|
||||
break;
|
||||
case JANET_TUPLE:
|
||||
janet_mark_tuple(janet_unwrap_tuple(x));
|
||||
break;
|
||||
case JANET_BUFFER:
|
||||
janet_mark_buffer(janet_unwrap_buffer(x));
|
||||
break;
|
||||
case JANET_FIBER:
|
||||
janet_mark_fiber(janet_unwrap_fiber(x));
|
||||
break;
|
||||
case JANET_ABSTRACT:
|
||||
janet_mark_abstract(janet_unwrap_abstract(x));
|
||||
break;
|
||||
}
|
||||
depth++;
|
||||
} else {
|
||||
@@ -80,7 +97,7 @@ void janet_mark(Janet x) {
|
||||
}
|
||||
|
||||
static void janet_mark_string(const uint8_t *str) {
|
||||
janet_gc_mark(janet_string_raw(str));
|
||||
janet_gc_mark(janet_string_head(str));
|
||||
}
|
||||
|
||||
static void janet_mark_buffer(JanetBuffer *buffer) {
|
||||
@@ -88,16 +105,26 @@ static void janet_mark_buffer(JanetBuffer *buffer) {
|
||||
}
|
||||
|
||||
static void janet_mark_abstract(void *adata) {
|
||||
if (janet_gc_reachable(janet_abstract_header(adata)))
|
||||
#ifdef JANET_EV
|
||||
/* Check if abstract type is a threaded abstract type. If it is, marking means
|
||||
* updating the threaded_abstract table. */
|
||||
if ((janet_abstract_head(adata)->gc.flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_THREADED_ABSTRACT) {
|
||||
janet_table_put(&janet_vm.threaded_abstracts, janet_wrap_abstract(adata), janet_wrap_true());
|
||||
return;
|
||||
janet_gc_mark(janet_abstract_header(adata));
|
||||
if (janet_abstract_header(adata)->type->gcmark) {
|
||||
janet_abstract_header(adata)->type->gcmark(adata, janet_abstract_size(adata));
|
||||
}
|
||||
#endif
|
||||
if (janet_gc_reachable(janet_abstract_head(adata)))
|
||||
return;
|
||||
janet_gc_mark(janet_abstract_head(adata));
|
||||
if (janet_abstract_head(adata)->type->gcmark) {
|
||||
janet_abstract_head(adata)->type->gcmark(adata, janet_abstract_size(adata));
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark a bunch of items in memory */
|
||||
static void janet_mark_many(const Janet *values, int32_t n) {
|
||||
if (values == NULL)
|
||||
return;
|
||||
const Janet *end = values + n;
|
||||
while (values < end) {
|
||||
janet_mark(*values);
|
||||
@@ -123,7 +150,7 @@ static void janet_mark_array(JanetArray *array) {
|
||||
}
|
||||
|
||||
static void janet_mark_table(JanetTable *table) {
|
||||
recur: /* Manual tail recursion */
|
||||
recur: /* Manual tail recursion */
|
||||
if (janet_gc_reachable(table))
|
||||
return;
|
||||
janet_gc_mark(table);
|
||||
@@ -135,16 +162,19 @@ static void janet_mark_table(JanetTable *table) {
|
||||
}
|
||||
|
||||
static void janet_mark_struct(const JanetKV *st) {
|
||||
if (janet_gc_reachable(janet_struct_raw(st)))
|
||||
recur:
|
||||
if (janet_gc_reachable(janet_struct_head(st)))
|
||||
return;
|
||||
janet_gc_mark(janet_struct_raw(st));
|
||||
janet_gc_mark(janet_struct_head(st));
|
||||
janet_mark_kvs(st, janet_struct_capacity(st));
|
||||
st = janet_struct_proto(st);
|
||||
if (st) goto recur;
|
||||
}
|
||||
|
||||
static void janet_mark_tuple(const Janet *tuple) {
|
||||
if (janet_gc_reachable(janet_tuple_raw(tuple)))
|
||||
if (janet_gc_reachable(janet_tuple_head(tuple)))
|
||||
return;
|
||||
janet_gc_mark(janet_tuple_raw(tuple));
|
||||
janet_gc_mark(janet_tuple_head(tuple));
|
||||
janet_mark_many(tuple, janet_tuple_length(tuple));
|
||||
}
|
||||
|
||||
@@ -153,7 +183,10 @@ static void janet_mark_funcenv(JanetFuncEnv *env) {
|
||||
if (janet_gc_reachable(env))
|
||||
return;
|
||||
janet_gc_mark(env);
|
||||
if (env->offset) {
|
||||
/* If closure env references a dead fiber, we can just copy out the stack frame we need so
|
||||
* we don't need to keep around the whole dead fiber. */
|
||||
janet_env_maybe_detach(env);
|
||||
if (env->offset > 0) {
|
||||
/* On stack */
|
||||
janet_mark_fiber(env->as.fiber);
|
||||
} else {
|
||||
@@ -176,6 +209,12 @@ static void janet_mark_funcdef(JanetFuncDef *def) {
|
||||
janet_mark_string(def->source);
|
||||
if (def->name)
|
||||
janet_mark_string(def->name);
|
||||
if (def->symbolmap) {
|
||||
for (int i = 0; i < def->symbolmap_length; i++) {
|
||||
janet_mark_string(def->symbolmap[i].symbol);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void janet_mark_function(JanetFunction *func) {
|
||||
@@ -184,11 +223,14 @@ static void janet_mark_function(JanetFunction *func) {
|
||||
if (janet_gc_reachable(func))
|
||||
return;
|
||||
janet_gc_mark(func);
|
||||
numenvs = func->def->environments_length;
|
||||
for (i = 0; i < numenvs; ++i) {
|
||||
janet_mark_funcenv(func->envs[i]);
|
||||
if (NULL != func->def) {
|
||||
/* this should always be true, except if function is only partially constructed */
|
||||
numenvs = func->def->environments_length;
|
||||
for (i = 0; i < numenvs; ++i) {
|
||||
janet_mark_funcenv(func->envs[i]);
|
||||
}
|
||||
janet_mark_funcdef(func->def);
|
||||
}
|
||||
janet_mark_funcdef(func->def);
|
||||
}
|
||||
|
||||
static void janet_mark_fiber(JanetFiber *fiber) {
|
||||
@@ -199,9 +241,11 @@ recur:
|
||||
return;
|
||||
janet_gc_mark(fiber);
|
||||
|
||||
janet_mark(fiber->last_value);
|
||||
|
||||
/* Mark values on the argument stack */
|
||||
janet_mark_many(fiber->data + fiber->stackstart,
|
||||
fiber->stacktop - fiber->stackstart);
|
||||
fiber->stacktop - fiber->stackstart);
|
||||
|
||||
i = fiber->frame;
|
||||
j = fiber->stackstart - JANET_FRAME_SIZE;
|
||||
@@ -217,6 +261,15 @@ recur:
|
||||
i = frame->prevframe;
|
||||
}
|
||||
|
||||
if (fiber->env)
|
||||
janet_mark_table(fiber->env);
|
||||
|
||||
#ifdef JANET_EV
|
||||
if (fiber->supervisor_channel) {
|
||||
janet_mark_abstract(fiber->supervisor_channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Explicit tail recursion */
|
||||
if (fiber->child) {
|
||||
fiber = fiber->child;
|
||||
@@ -225,136 +278,204 @@ recur:
|
||||
}
|
||||
|
||||
/* Deinitialize a block of memory */
|
||||
static void janet_deinit_block(JanetGCMemoryHeader *block) {
|
||||
void *mem = ((char *)(block + 1));
|
||||
JanetAbstractHeader *h = (JanetAbstractHeader *)mem;
|
||||
switch (block->flags & JANET_MEM_TYPEBITS) {
|
||||
static void janet_deinit_block(JanetGCObject *mem) {
|
||||
switch (mem->flags & JANET_MEM_TYPEBITS) {
|
||||
default:
|
||||
case JANET_MEMORY_FUNCTION:
|
||||
break; /* Do nothing for non gc types */
|
||||
case JANET_MEMORY_SYMBOL:
|
||||
janet_symbol_deinit((const uint8_t *)mem + 2 * sizeof(int32_t));
|
||||
janet_symbol_deinit(((JanetStringHead *) mem)->data);
|
||||
break;
|
||||
case JANET_MEMORY_ARRAY:
|
||||
janet_array_deinit((JanetArray*) mem);
|
||||
janet_free(((JanetArray *) mem)->data);
|
||||
break;
|
||||
case JANET_MEMORY_TABLE:
|
||||
janet_table_deinit((JanetTable*) mem);
|
||||
janet_free(((JanetTable *) mem)->data);
|
||||
break;
|
||||
case JANET_MEMORY_FIBER:
|
||||
free(((JanetFiber *)mem)->data);
|
||||
janet_free(((JanetFiber *)mem)->data);
|
||||
break;
|
||||
case JANET_MEMORY_BUFFER:
|
||||
janet_buffer_deinit((JanetBuffer *) mem);
|
||||
break;
|
||||
case JANET_MEMORY_ABSTRACT:
|
||||
if (h->type->gc) {
|
||||
janet_assert(!h->type->gc((void *)(h + 1), h->size), "finalizer failed");
|
||||
case JANET_MEMORY_ABSTRACT: {
|
||||
JanetAbstractHead *head = (JanetAbstractHead *)mem;
|
||||
if (head->type->gc) {
|
||||
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
||||
}
|
||||
break;
|
||||
case JANET_MEMORY_FUNCENV:
|
||||
{
|
||||
JanetFuncEnv *env = (JanetFuncEnv *)mem;
|
||||
if (0 == env->offset)
|
||||
free(env->as.values);
|
||||
}
|
||||
break;
|
||||
case JANET_MEMORY_FUNCDEF:
|
||||
{
|
||||
JanetFuncDef *def = (JanetFuncDef *)mem;
|
||||
/* TODO - get this all with one alloc and one free */
|
||||
free(def->defs);
|
||||
free(def->environments);
|
||||
free(def->constants);
|
||||
free(def->bytecode);
|
||||
free(def->sourcemap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case JANET_MEMORY_FUNCENV: {
|
||||
JanetFuncEnv *env = (JanetFuncEnv *)mem;
|
||||
if (0 == env->offset)
|
||||
janet_free(env->as.values);
|
||||
}
|
||||
break;
|
||||
case JANET_MEMORY_FUNCDEF: {
|
||||
JanetFuncDef *def = (JanetFuncDef *)mem;
|
||||
/* TODO - get this all with one alloc and one free */
|
||||
janet_free(def->defs);
|
||||
janet_free(def->environments);
|
||||
janet_free(def->constants);
|
||||
janet_free(def->bytecode);
|
||||
janet_free(def->sourcemap);
|
||||
janet_free(def->closure_bitset);
|
||||
janet_free(def->symbolmap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over all allocated memory, and free memory that is not
|
||||
* marked as reachable. Flip the gc color flag for next sweep. */
|
||||
void janet_sweep() {
|
||||
JanetGCMemoryHeader *previous = NULL;
|
||||
JanetGCMemoryHeader *current = janet_vm_blocks;
|
||||
JanetGCMemoryHeader *next;
|
||||
JanetGCObject *previous = NULL;
|
||||
JanetGCObject *current = janet_vm.blocks;
|
||||
JanetGCObject *next;
|
||||
while (NULL != current) {
|
||||
next = current->next;
|
||||
next = current->data.next;
|
||||
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
|
||||
previous = current;
|
||||
current->flags &= ~JANET_MEM_REACHABLE;
|
||||
} else {
|
||||
janet_vm.block_count--;
|
||||
janet_deinit_block(current);
|
||||
if (NULL != previous) {
|
||||
previous->next = next;
|
||||
previous->data.next = next;
|
||||
} else {
|
||||
janet_vm_blocks = next;
|
||||
janet_vm.blocks = next;
|
||||
}
|
||||
free(current);
|
||||
janet_free(current);
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
#ifdef JANET_EV
|
||||
/* Sweep threaded abstract types for references to decrement */
|
||||
JanetKV *items = janet_vm.threaded_abstracts.data;
|
||||
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
|
||||
if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
|
||||
|
||||
/* If item was not visited during the mark phase, then this
|
||||
* abstract type isn't present in the heap and needs its refcount
|
||||
* decremented, and shouuld be removed from table. If the refcount is
|
||||
* then 0, the item will be collected. This ensures that only one interpreter
|
||||
* will clean up the threaded abstract. */
|
||||
|
||||
/* If not visited... */
|
||||
if (!janet_truthy(items[i].value)) {
|
||||
void *abst = janet_unwrap_abstract(items[i].key);
|
||||
if (0 == janet_abstract_decref(abst)) {
|
||||
/* Run finalizer */
|
||||
JanetAbstractHead *head = janet_abstract_head(abst);
|
||||
if (head->type->gc) {
|
||||
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
||||
}
|
||||
/* Mark as tombstone in place */
|
||||
items[i].key = janet_wrap_nil();
|
||||
items[i].value = janet_wrap_false();
|
||||
janet_vm.threaded_abstracts.deleted++;
|
||||
janet_vm.threaded_abstracts.count--;
|
||||
/* Free memory */
|
||||
janet_free(janet_abstract_head(abst));
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset for next sweep */
|
||||
items[i].value = janet_wrap_false();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Allocate some memory that is tracked for garbage collection */
|
||||
void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
|
||||
JanetGCMemoryHeader *mdata;
|
||||
size_t total = size + sizeof(JanetGCMemoryHeader);
|
||||
JanetGCObject *mem;
|
||||
|
||||
/* Make sure everything is inited */
|
||||
janet_assert(NULL != janet_vm_cache, "please initialize janet before use");
|
||||
void *mem = malloc(total);
|
||||
janet_assert(NULL != janet_vm.cache, "please initialize janet before use");
|
||||
mem = janet_malloc(size);
|
||||
|
||||
/* Check for bad malloc */
|
||||
if (NULL == mem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mdata = (JanetGCMemoryHeader *)mem;
|
||||
|
||||
/* Configure block */
|
||||
mdata->flags = type;
|
||||
mem->flags = type;
|
||||
|
||||
/* Prepend block to heap list */
|
||||
janet_vm_next_collection += (int32_t) size;
|
||||
mdata->next = janet_vm_blocks;
|
||||
janet_vm_blocks = mdata;
|
||||
janet_vm.next_collection += size;
|
||||
mem->data.next = janet_vm.blocks;
|
||||
janet_vm.blocks = mem;
|
||||
janet_vm.block_count++;
|
||||
|
||||
return (char *) mem + sizeof(JanetGCMemoryHeader);
|
||||
return (void *)mem;
|
||||
}
|
||||
|
||||
static void free_one_scratch(JanetScratch *s) {
|
||||
if (NULL != s->finalize) {
|
||||
s->finalize((char *) s->mem);
|
||||
}
|
||||
janet_free(s);
|
||||
}
|
||||
|
||||
/* Free all allocated scratch memory */
|
||||
static void janet_free_all_scratch(void) {
|
||||
for (size_t i = 0; i < janet_vm.scratch_len; i++) {
|
||||
free_one_scratch(janet_vm.scratch_mem[i]);
|
||||
}
|
||||
janet_vm.scratch_len = 0;
|
||||
}
|
||||
|
||||
static JanetScratch *janet_mem2scratch(void *mem) {
|
||||
JanetScratch *s = (JanetScratch *)mem;
|
||||
return s - 1;
|
||||
}
|
||||
|
||||
/* Run garbage collection */
|
||||
void janet_collect(void) {
|
||||
uint32_t i;
|
||||
if (janet_vm_gc_suspend) return;
|
||||
if (janet_vm.gc_suspend) return;
|
||||
depth = JANET_RECURSION_GUARD;
|
||||
orig_rootcount = janet_vm_root_count;
|
||||
/* Try and prevent many major collections back to back.
|
||||
* A full collection will take O(janet_vm.block_count) time.
|
||||
* If we have a large heap, make sure our interval is not too
|
||||
* small so we won't make many collections over it. This is just a
|
||||
* heuristic for automatically changing the gc interval */
|
||||
if (janet_vm.block_count * 8 > janet_vm.gc_interval) {
|
||||
janet_vm.gc_interval = janet_vm.block_count * sizeof(JanetGCObject);
|
||||
}
|
||||
orig_rootcount = janet_vm.root_count;
|
||||
#ifdef JANET_EV
|
||||
janet_ev_mark();
|
||||
#endif
|
||||
janet_mark_fiber(janet_vm.root_fiber);
|
||||
for (i = 0; i < orig_rootcount; i++)
|
||||
janet_mark(janet_vm_roots[i]);
|
||||
while (orig_rootcount < janet_vm_root_count) {
|
||||
Janet x = janet_vm_roots[--janet_vm_root_count];
|
||||
janet_mark(janet_vm.roots[i]);
|
||||
while (orig_rootcount < janet_vm.root_count) {
|
||||
Janet x = janet_vm.roots[--janet_vm.root_count];
|
||||
janet_mark(x);
|
||||
}
|
||||
janet_sweep();
|
||||
janet_vm_next_collection = 0;
|
||||
janet_vm.next_collection = 0;
|
||||
janet_free_all_scratch();
|
||||
}
|
||||
|
||||
/* Add a root value to the GC. This prevents the GC from removing a value
|
||||
* and all of its children. If gcroot is called on a value n times, unroot
|
||||
* must also be called n times to remove it as a gc root. */
|
||||
void janet_gcroot(Janet root) {
|
||||
uint32_t newcount = janet_vm_root_count + 1;
|
||||
if (newcount > janet_vm_root_capacity) {
|
||||
uint32_t newcap = 2 * newcount;
|
||||
janet_vm_roots = realloc(janet_vm_roots, sizeof(Janet) * newcap);
|
||||
if (NULL == janet_vm_roots) {
|
||||
size_t newcount = janet_vm.root_count + 1;
|
||||
if (newcount > janet_vm.root_capacity) {
|
||||
size_t newcap = 2 * newcount;
|
||||
janet_vm.roots = janet_realloc(janet_vm.roots, sizeof(Janet) * newcap);
|
||||
if (NULL == janet_vm.roots) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_root_capacity = newcap;
|
||||
janet_vm.root_capacity = newcap;
|
||||
}
|
||||
janet_vm_roots[janet_vm_root_count] = root;
|
||||
janet_vm_root_count = newcount;
|
||||
janet_vm.roots[janet_vm.root_count] = root;
|
||||
janet_vm.root_count = newcount;
|
||||
}
|
||||
|
||||
/* Identity equality for GC purposes */
|
||||
@@ -362,8 +483,7 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
|
||||
if (janet_type(lhs) != janet_type(rhs))
|
||||
return 0;
|
||||
switch (janet_type(lhs)) {
|
||||
case JANET_TRUE:
|
||||
case JANET_FALSE:
|
||||
case JANET_BOOLEAN:
|
||||
case JANET_NIL:
|
||||
case JANET_NUMBER:
|
||||
/* These values don't really matter to the gc so returning 1 all the time is fine. */
|
||||
@@ -376,12 +496,11 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
|
||||
/* Remove a root value from the GC. This allows the gc to potentially reclaim
|
||||
* a value and all its children. */
|
||||
int janet_gcunroot(Janet root) {
|
||||
Janet *vtop = janet_vm_roots + janet_vm_root_count;
|
||||
Janet *v = janet_vm_roots;
|
||||
Janet *vtop = janet_vm.roots + janet_vm.root_count;
|
||||
/* Search from top to bottom as access is most likely LIFO */
|
||||
for (v = janet_vm_roots; v < vtop; v++) {
|
||||
for (Janet *v = janet_vm.roots; v < vtop; v++) {
|
||||
if (janet_gc_idequals(root, *v)) {
|
||||
*v = janet_vm_roots[--janet_vm_root_count];
|
||||
*v = janet_vm.roots[--janet_vm.root_count];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -390,13 +509,12 @@ int janet_gcunroot(Janet root) {
|
||||
|
||||
/* Remove a root value from the GC. This sets the effective reference count to 0. */
|
||||
int janet_gcunrootall(Janet root) {
|
||||
Janet *vtop = janet_vm_roots + janet_vm_root_count;
|
||||
Janet *v = janet_vm_roots;
|
||||
Janet *vtop = janet_vm.roots + janet_vm.root_count;
|
||||
int ret = 0;
|
||||
/* Search from top to bottom as access is most likely LIFO */
|
||||
for (v = janet_vm_roots; v < vtop; v++) {
|
||||
for (Janet *v = janet_vm.roots; v < vtop; v++) {
|
||||
if (janet_gc_idequals(root, *v)) {
|
||||
*v = janet_vm_roots[--janet_vm_root_count];
|
||||
*v = janet_vm.roots[--janet_vm.root_count];
|
||||
vtop--;
|
||||
ret = 1;
|
||||
}
|
||||
@@ -406,16 +524,108 @@ int janet_gcunrootall(Janet root) {
|
||||
|
||||
/* Free all allocated memory */
|
||||
void janet_clear_memory(void) {
|
||||
JanetGCMemoryHeader *current = janet_vm_blocks;
|
||||
#ifdef JANET_EV
|
||||
JanetKV *items = janet_vm.threaded_abstracts.data;
|
||||
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
|
||||
if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
|
||||
void *abst = janet_unwrap_abstract(items[i].key);
|
||||
if (0 == janet_abstract_decref(abst)) {
|
||||
JanetAbstractHead *head = janet_abstract_head(abst);
|
||||
if (head->type->gc) {
|
||||
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
||||
}
|
||||
janet_free(janet_abstract_head(abst));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
JanetGCObject *current = janet_vm.blocks;
|
||||
while (NULL != current) {
|
||||
janet_deinit_block(current);
|
||||
JanetGCMemoryHeader *next = current->next;
|
||||
free(current);
|
||||
JanetGCObject *next = current->data.next;
|
||||
janet_free(current);
|
||||
current = next;
|
||||
}
|
||||
janet_vm_blocks = NULL;
|
||||
janet_vm.blocks = NULL;
|
||||
janet_free_all_scratch();
|
||||
janet_free(janet_vm.scratch_mem);
|
||||
}
|
||||
|
||||
/* Primitives for suspending GC. */
|
||||
int janet_gclock(void) { return janet_vm_gc_suspend++; }
|
||||
void janet_gcunlock(int handle) { janet_vm_gc_suspend = handle; }
|
||||
int janet_gclock(void) {
|
||||
return janet_vm.gc_suspend++;
|
||||
}
|
||||
void janet_gcunlock(int handle) {
|
||||
janet_vm.gc_suspend = handle;
|
||||
}
|
||||
|
||||
/* Scratch memory API */
|
||||
|
||||
void *janet_smalloc(size_t size) {
|
||||
JanetScratch *s = janet_malloc(sizeof(JanetScratch) + size);
|
||||
if (NULL == s) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
s->finalize = NULL;
|
||||
if (janet_vm.scratch_len == janet_vm.scratch_cap) {
|
||||
size_t newcap = 2 * janet_vm.scratch_cap + 2;
|
||||
JanetScratch **newmem = (JanetScratch **) janet_realloc(janet_vm.scratch_mem, newcap * sizeof(JanetScratch));
|
||||
if (NULL == newmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm.scratch_cap = newcap;
|
||||
janet_vm.scratch_mem = newmem;
|
||||
}
|
||||
janet_vm.scratch_mem[janet_vm.scratch_len++] = s;
|
||||
return (char *)(s->mem);
|
||||
}
|
||||
|
||||
void *janet_scalloc(size_t nmemb, size_t size) {
|
||||
if (nmemb && size > SIZE_MAX / nmemb) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
size_t n = nmemb * size;
|
||||
void *p = janet_smalloc(n);
|
||||
memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *janet_srealloc(void *mem, size_t size) {
|
||||
if (NULL == mem) return janet_smalloc(size);
|
||||
JanetScratch *s = janet_mem2scratch(mem);
|
||||
if (janet_vm.scratch_len) {
|
||||
for (size_t i = janet_vm.scratch_len - 1; ; i--) {
|
||||
if (janet_vm.scratch_mem[i] == s) {
|
||||
JanetScratch *news = janet_realloc(s, size + sizeof(JanetScratch));
|
||||
if (NULL == news) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm.scratch_mem[i] = news;
|
||||
return (char *)(news->mem);
|
||||
}
|
||||
if (i == 0) break;
|
||||
}
|
||||
}
|
||||
JANET_EXIT("invalid janet_srealloc");
|
||||
}
|
||||
|
||||
void janet_sfinalizer(void *mem, JanetScratchFinalizer finalizer) {
|
||||
JanetScratch *s = janet_mem2scratch(mem);
|
||||
s->finalize = finalizer;
|
||||
}
|
||||
|
||||
void janet_sfree(void *mem) {
|
||||
if (NULL == mem) return;
|
||||
JanetScratch *s = janet_mem2scratch(mem);
|
||||
if (janet_vm.scratch_len) {
|
||||
for (size_t i = janet_vm.scratch_len - 1; ; i--) {
|
||||
if (janet_vm.scratch_mem[i] == s) {
|
||||
janet_vm.scratch_mem[i] = janet_vm.scratch_mem[--janet_vm.scratch_len];
|
||||
free_one_scratch(s);
|
||||
return;
|
||||
}
|
||||
if (i == 0) break;
|
||||
}
|
||||
}
|
||||
JANET_EXIT("invalid janet_sfree");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -24,11 +24,12 @@
|
||||
#define JANET_GC_H
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#endif
|
||||
|
||||
/* The metadata header associated with an allocated block of memory */
|
||||
#define janet_gc_header(mem) ((JanetGCMemoryHeader *)(mem) - 1)
|
||||
#define janet_gc_header(mem) ((JanetGCObject *)(mem))
|
||||
|
||||
#define JANET_MEM_TYPEBITS 0xFF
|
||||
#define JANET_MEM_REACHABLE 0x100
|
||||
@@ -40,13 +41,6 @@
|
||||
#define janet_gc_mark(m) (janet_gc_header(m)->flags |= JANET_MEM_REACHABLE)
|
||||
#define janet_gc_reachable(m) (janet_gc_header(m)->flags & JANET_MEM_REACHABLE)
|
||||
|
||||
/* Memory header struct. Node of a linked list of memory blocks. */
|
||||
typedef struct JanetGCMemoryHeader JanetGCMemoryHeader;
|
||||
struct JanetGCMemoryHeader {
|
||||
JanetGCMemoryHeader *next;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/* Memory types for the GC. Different from JanetType to include funcenv and funcdef. */
|
||||
enum JanetMemoryType {
|
||||
JANET_MEMORY_NONE,
|
||||
@@ -61,10 +55,11 @@ enum JanetMemoryType {
|
||||
JANET_MEMORY_FUNCTION,
|
||||
JANET_MEMORY_ABSTRACT,
|
||||
JANET_MEMORY_FUNCENV,
|
||||
JANET_MEMORY_FUNCDEF
|
||||
JANET_MEMORY_FUNCDEF,
|
||||
JANET_MEMORY_THREADED_ABSTRACT,
|
||||
};
|
||||
|
||||
/* To allocate collectable memory, one must calk janet_alloc, initialize the memory,
|
||||
/* To allocate collectable memory, one must call janet_alloc, initialize the memory,
|
||||
* and then call when janet_enablegc when it is initailize and reachable by the gc (on the JANET stack) */
|
||||
void *janet_gcalloc(enum JanetMemoryType type, size_t size);
|
||||
|
||||
|
||||
686
src/core/inttypes.c
Normal file
686
src/core/inttypes.c
Normal file
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Calvin Rose & contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Conditional compilation */
|
||||
#ifdef JANET_INT_TYPES
|
||||
|
||||
#define MAX_INT_IN_DBL 9007199254740992ULL /* 2^53 */
|
||||
|
||||
static int it_s64_get(void *p, Janet key, Janet *out);
|
||||
static int it_u64_get(void *p, Janet key, Janet *out);
|
||||
static Janet janet_int64_next(void *p, Janet key);
|
||||
static Janet janet_uint64_next(void *p, Janet key);
|
||||
|
||||
static int32_t janet_int64_hash(void *p1, size_t size) {
|
||||
(void) size;
|
||||
int32_t *words = p1;
|
||||
return words[0] ^ words[1];
|
||||
}
|
||||
|
||||
static int janet_int64_compare(void *p1, void *p2) {
|
||||
int64_t x = *((int64_t *)p1);
|
||||
int64_t y = *((int64_t *)p2);
|
||||
return x == y ? 0 : x < y ? -1 : 1;
|
||||
}
|
||||
|
||||
static int janet_uint64_compare(void *p1, void *p2) {
|
||||
uint64_t x = *((uint64_t *)p1);
|
||||
uint64_t y = *((uint64_t *)p2);
|
||||
return x == y ? 0 : x < y ? -1 : 1;
|
||||
}
|
||||
|
||||
static void int64_marshal(void *p, JanetMarshalContext *ctx) {
|
||||
janet_marshal_abstract(ctx, p);
|
||||
janet_marshal_int64(ctx, *((int64_t *)p));
|
||||
}
|
||||
|
||||
static void *int64_unmarshal(JanetMarshalContext *ctx) {
|
||||
int64_t *p = janet_unmarshal_abstract(ctx, sizeof(int64_t));
|
||||
p[0] = janet_unmarshal_int64(ctx);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void it_s64_tostring(void *p, JanetBuffer *buffer) {
|
||||
char str[32];
|
||||
sprintf(str, "%" PRId64, *((int64_t *)p));
|
||||
janet_buffer_push_cstring(buffer, str);
|
||||
}
|
||||
|
||||
static void it_u64_tostring(void *p, JanetBuffer *buffer) {
|
||||
char str[32];
|
||||
sprintf(str, "%" PRIu64, *((uint64_t *)p));
|
||||
janet_buffer_push_cstring(buffer, str);
|
||||
}
|
||||
|
||||
const JanetAbstractType janet_s64_type = {
|
||||
"core/s64",
|
||||
NULL,
|
||||
NULL,
|
||||
it_s64_get,
|
||||
NULL,
|
||||
int64_marshal,
|
||||
int64_unmarshal,
|
||||
it_s64_tostring,
|
||||
janet_int64_compare,
|
||||
janet_int64_hash,
|
||||
janet_int64_next,
|
||||
JANET_ATEND_NEXT
|
||||
};
|
||||
|
||||
const JanetAbstractType janet_u64_type = {
|
||||
"core/u64",
|
||||
NULL,
|
||||
NULL,
|
||||
it_u64_get,
|
||||
NULL,
|
||||
int64_marshal,
|
||||
int64_unmarshal,
|
||||
it_u64_tostring,
|
||||
janet_uint64_compare,
|
||||
janet_int64_hash,
|
||||
janet_uint64_next,
|
||||
JANET_ATEND_NEXT
|
||||
};
|
||||
|
||||
int64_t janet_unwrap_s64(Janet x) {
|
||||
switch (janet_type(x)) {
|
||||
default:
|
||||
break;
|
||||
case JANET_NUMBER : {
|
||||
double dbl = janet_unwrap_number(x);
|
||||
if (fabs(dbl) <= MAX_INT_IN_DBL)
|
||||
return (int64_t)dbl;
|
||||
break;
|
||||
}
|
||||
case JANET_STRING: {
|
||||
int64_t value;
|
||||
const uint8_t *str = janet_unwrap_string(x);
|
||||
if (janet_scan_int64(str, janet_string_length(str), &value))
|
||||
return value;
|
||||
break;
|
||||
}
|
||||
case JANET_ABSTRACT: {
|
||||
void *abst = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abst) == &janet_s64_type ||
|
||||
(janet_abstract_type(abst) == &janet_u64_type))
|
||||
return *(int64_t *)abst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
janet_panicf("can not convert %t %q to 64 bit signed integer", x, x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t janet_unwrap_u64(Janet x) {
|
||||
switch (janet_type(x)) {
|
||||
default:
|
||||
break;
|
||||
case JANET_NUMBER : {
|
||||
double dbl = janet_unwrap_number(x);
|
||||
/* Allow negative values to be cast to "wrap around".
|
||||
* This let's addition and subtraction work as expected. */
|
||||
if (fabs(dbl) <= MAX_INT_IN_DBL)
|
||||
return (uint64_t)dbl;
|
||||
break;
|
||||
}
|
||||
case JANET_STRING: {
|
||||
uint64_t value;
|
||||
const uint8_t *str = janet_unwrap_string(x);
|
||||
if (janet_scan_uint64(str, janet_string_length(str), &value))
|
||||
return value;
|
||||
break;
|
||||
}
|
||||
case JANET_ABSTRACT: {
|
||||
void *abst = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abst) == &janet_s64_type ||
|
||||
(janet_abstract_type(abst) == &janet_u64_type))
|
||||
return *(uint64_t *)abst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
janet_panicf("can not convert %t %q to a 64 bit unsigned integer", x, x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JanetIntType janet_is_int(Janet x) {
|
||||
if (!janet_checktype(x, JANET_ABSTRACT)) return JANET_INT_NONE;
|
||||
const JanetAbstractType *at = janet_abstract_type(janet_unwrap_abstract(x));
|
||||
return (at == &janet_s64_type) ? JANET_INT_S64 :
|
||||
((at == &janet_u64_type) ? JANET_INT_U64 :
|
||||
JANET_INT_NONE);
|
||||
}
|
||||
|
||||
Janet janet_wrap_s64(int64_t x) {
|
||||
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||
*box = (int64_t)x;
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
Janet janet_wrap_u64(uint64_t x) {
|
||||
uint64_t *box = janet_abstract(&janet_u64_type, sizeof(uint64_t));
|
||||
*box = (uint64_t)x;
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_it_s64_new,
|
||||
"(int/s64 value)",
|
||||
"Create a boxed signed 64 bit integer from a string value.") {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_s64(janet_unwrap_s64(argv[0]));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_it_u64_new,
|
||||
"(int/u64 value)",
|
||||
"Create a boxed unsigned 64 bit integer from a string value.") {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_u64(janet_unwrap_u64(argv[0]));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_to_number,
|
||||
"(int/to-number value)",
|
||||
"Convert an int/u64 or int/s64 to a number. Fails if the number is out of range for an int32.") {
|
||||
janet_fixarity(argc, 1);
|
||||
if (janet_type(argv[0]) == JANET_ABSTRACT) {
|
||||
void *abst = janet_unwrap_abstract(argv[0]);
|
||||
|
||||
if (janet_abstract_type(abst) == &janet_s64_type) {
|
||||
int64_t value = *((int64_t *)abst);
|
||||
if (value > JANET_INTMAX_INT64) {
|
||||
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
|
||||
}
|
||||
if (value < -JANET_INTMAX_INT64) {
|
||||
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
|
||||
}
|
||||
return janet_wrap_number((double)value);
|
||||
}
|
||||
|
||||
if (janet_abstract_type(abst) == &janet_u64_type) {
|
||||
uint64_t value = *((uint64_t *)abst);
|
||||
if (value > JANET_INTMAX_INT64) {
|
||||
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
|
||||
}
|
||||
|
||||
return janet_wrap_number((double)value);
|
||||
}
|
||||
}
|
||||
|
||||
janet_panicf("expected int/u64 or int/s64, got %q", argv[0]);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_to_bytes,
|
||||
"(int/to-bytes value &opt endianness buffer)",
|
||||
"Write the bytes of an `int/s64` or `int/u64` into a buffer.\n"
|
||||
"The `buffer` parameter specifies an existing buffer to write to, if unset a new buffer will be created.\n"
|
||||
"Returns the modified buffer.\n"
|
||||
"The `endianness` paramater indicates the byte order:\n"
|
||||
"- `nil` (unset): system byte order\n"
|
||||
"- `:le`: little-endian, least significant byte first\n"
|
||||
"- `:be`: big-endian, most significant byte first\n") {
|
||||
janet_arity(argc, 1, 3);
|
||||
if (janet_is_int(argv[0]) == JANET_INT_NONE) {
|
||||
janet_panicf("int/to-bytes: expected an int/s64 or int/u64, got %q", argv[0]);
|
||||
}
|
||||
|
||||
int reverse = 0;
|
||||
if (argc > 1 && !janet_checktype(argv[1], JANET_NIL)) {
|
||||
JanetKeyword endianness_kw = janet_getkeyword(argv, 1);
|
||||
if (!janet_cstrcmp(endianness_kw, "le")) {
|
||||
#if JANET_BIG_ENDIAN
|
||||
reverse = 1;
|
||||
#endif
|
||||
} else if (!janet_cstrcmp(endianness_kw, "be")) {
|
||||
#if JANET_LITTLE_ENDIAN
|
||||
reverse = 1;
|
||||
#endif
|
||||
} else {
|
||||
janet_panicf("int/to-bytes: expected endianness :le, :be or nil, got %v", argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
JanetBuffer *buffer = NULL;
|
||||
if (argc > 2 && !janet_checktype(argv[2], JANET_NIL)) {
|
||||
if (!janet_checktype(argv[2], JANET_BUFFER)) {
|
||||
janet_panicf("int/to-bytes: expected buffer or nil, got %q", argv[2]);
|
||||
}
|
||||
|
||||
buffer = janet_unwrap_buffer(argv[2]);
|
||||
janet_buffer_extra(buffer, 8);
|
||||
} else {
|
||||
buffer = janet_buffer(8);
|
||||
}
|
||||
|
||||
uint8_t *bytes = janet_unwrap_abstract(argv[0]);
|
||||
if (reverse) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
buffer->data[buffer->count + 7 - i] = bytes[i];
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer->data + buffer->count, bytes, 8);
|
||||
}
|
||||
buffer->count += 8;
|
||||
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Code to support polymorphic comparison.
|
||||
* int/u64 and int/s64 support a "compare" method that allows
|
||||
* comparison to each other, and to Janet numbers, using the
|
||||
* "compare" "compare<" ... functions.
|
||||
* In the following code explicit casts are sometimes used to help
|
||||
* make it clear when int/float conversions are happening.
|
||||
*/
|
||||
static int compare_double_double(double x, double y) {
|
||||
return (x < y) ? -1 : ((x > y) ? 1 : 0);
|
||||
}
|
||||
|
||||
static int compare_int64_double(int64_t x, double y) {
|
||||
if (isnan(y)) {
|
||||
return 0; // clojure and python do this
|
||||
} else if ((y > (- ((double) MAX_INT_IN_DBL))) && (y < ((double) MAX_INT_IN_DBL))) {
|
||||
double dx = (double) x;
|
||||
return compare_double_double(dx, y);
|
||||
} else if (y > ((double) INT64_MAX)) {
|
||||
return -1;
|
||||
} else if (y < ((double) INT64_MIN)) {
|
||||
return 1;
|
||||
} else {
|
||||
int64_t yi = (int64_t) y;
|
||||
return (x < yi) ? -1 : ((x > yi) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int compare_uint64_double(uint64_t x, double y) {
|
||||
if (isnan(y)) {
|
||||
return 0; // clojure and python do this
|
||||
} else if (y < 0) {
|
||||
return 1;
|
||||
} else if ((y >= 0) && (y < ((double) MAX_INT_IN_DBL))) {
|
||||
double dx = (double) x;
|
||||
return compare_double_double(dx, y);
|
||||
} else if (y > ((double) UINT64_MAX)) {
|
||||
return -1;
|
||||
} else {
|
||||
uint64_t yi = (uint64_t) y;
|
||||
return (x < yi) ? -1 : ((x > yi) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
static Janet cfun_it_s64_compare(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
if (janet_is_int(argv[0]) != JANET_INT_S64)
|
||||
janet_panic("compare method requires int/s64 as first argument");
|
||||
int64_t x = janet_unwrap_s64(argv[0]);
|
||||
switch (janet_type(argv[1])) {
|
||||
default:
|
||||
break;
|
||||
case JANET_NUMBER : {
|
||||
double y = janet_unwrap_number(argv[1]);
|
||||
return janet_wrap_number(compare_int64_double(x, y));
|
||||
}
|
||||
case JANET_ABSTRACT: {
|
||||
void *abst = janet_unwrap_abstract(argv[1]);
|
||||
if (janet_abstract_type(abst) == &janet_s64_type) {
|
||||
int64_t y = *(int64_t *)abst;
|
||||
return janet_wrap_number((x < y) ? -1 : (x > y ? 1 : 0));
|
||||
} else if (janet_abstract_type(abst) == &janet_u64_type) {
|
||||
// comparing signed to unsigned -- be careful!
|
||||
uint64_t y = *(uint64_t *)abst;
|
||||
if (x < 0) {
|
||||
return janet_wrap_number(-1);
|
||||
} else if (y > INT64_MAX) {
|
||||
return janet_wrap_number(-1);
|
||||
} else {
|
||||
int64_t y2 = (int64_t) y;
|
||||
return janet_wrap_number((x < y2) ? -1 : (x > y2 ? 1 : 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_it_u64_compare(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
if (janet_is_int(argv[0]) != JANET_INT_U64) // is this needed?
|
||||
janet_panic("compare method requires int/u64 as first argument");
|
||||
uint64_t x = janet_unwrap_u64(argv[0]);
|
||||
switch (janet_type(argv[1])) {
|
||||
default:
|
||||
break;
|
||||
case JANET_NUMBER : {
|
||||
double y = janet_unwrap_number(argv[1]);
|
||||
return janet_wrap_number(compare_uint64_double(x, y));
|
||||
}
|
||||
case JANET_ABSTRACT: {
|
||||
void *abst = janet_unwrap_abstract(argv[1]);
|
||||
if (janet_abstract_type(abst) == &janet_u64_type) {
|
||||
uint64_t y = *(uint64_t *)abst;
|
||||
return janet_wrap_number((x < y) ? -1 : (x > y ? 1 : 0));
|
||||
} else if (janet_abstract_type(abst) == &janet_s64_type) {
|
||||
// comparing unsigned to signed -- be careful!
|
||||
int64_t y = *(int64_t *)abst;
|
||||
if (y < 0) {
|
||||
return janet_wrap_number(1);
|
||||
} else if (x > INT64_MAX) {
|
||||
return janet_wrap_number(1);
|
||||
} else {
|
||||
int64_t x2 = (int64_t) x;
|
||||
return janet_wrap_number((x2 < y) ? -1 : (x2 > y ? 1 : 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
/*
|
||||
* In C, signed arithmetic overflow is undefined behvior
|
||||
* but unsigned arithmetic overflow is twos complement
|
||||
*
|
||||
* Reference:
|
||||
* https://en.cppreference.com/w/cpp/language/ub
|
||||
* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
|
||||
*
|
||||
* This means OPMETHOD & OPMETHODINVERT must always use
|
||||
* unsigned arithmetic internally, regardless of the true type.
|
||||
* This will not affect the end result (property of twos complement).
|
||||
*/
|
||||
#define OPMETHOD(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||
janet_arity(argc, 2, -1); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[0]); \
|
||||
for (int32_t i = 1; i < argc; i++) \
|
||||
/* This avoids undefined behavior. See above for why. */ \
|
||||
*box = (T) ((uint64_t) (*box)) oper ((uint64_t) janet_unwrap_##type(argv[i])); \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define OPMETHODINVERT(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name##i(int32_t argc, Janet *argv) { \
|
||||
janet_fixarity(argc, 2); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[1]); \
|
||||
/* This avoids undefined behavior. See above for why. */ \
|
||||
*box = (T) ((uint64_t) *box) oper ((uint64_t) janet_unwrap_##type(argv[0])); \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define UNARYMETHOD(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||
janet_fixarity(argc, 1); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = oper(janet_unwrap_##type(argv[0])); \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define DIVZERO(name) DIVZERO_##name
|
||||
#define DIVZERO_div janet_panic("division by zero")
|
||||
#define DIVZERO_rem janet_panic("division by zero")
|
||||
#define DIVZERO_mod return janet_wrap_abstract(box)
|
||||
|
||||
#define DIVMETHOD(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||
janet_arity(argc, 2, -1); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[0]); \
|
||||
for (int32_t i = 1; i < argc; i++) { \
|
||||
T value = janet_unwrap_##type(argv[i]); \
|
||||
if (value == 0) DIVZERO(name); \
|
||||
*box oper##= value; \
|
||||
} \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define DIVMETHODINVERT(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name##i(int32_t argc, Janet *argv) { \
|
||||
janet_fixarity(argc, 2); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[1]); \
|
||||
T value = janet_unwrap_##type(argv[0]); \
|
||||
if (value == 0) DIVZERO(name); \
|
||||
*box oper##= value; \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define DIVMETHOD_SIGNED(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||
janet_arity(argc, 2, -1); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[0]); \
|
||||
for (int32_t i = 1; i < argc; i++) { \
|
||||
T value = janet_unwrap_##type(argv[i]); \
|
||||
if (value == 0) DIVZERO(name); \
|
||||
if ((value == -1) && (*box == INT64_MIN)) janet_panic("INT64_MIN divided by -1"); \
|
||||
*box oper##= value; \
|
||||
} \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define DIVMETHODINVERT_SIGNED(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name##i(int32_t argc, Janet *argv) { \
|
||||
janet_fixarity(argc, 2); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[1]); \
|
||||
T value = janet_unwrap_##type(argv[0]); \
|
||||
if (value == 0) DIVZERO(name); \
|
||||
if ((value == -1) && (*box == INT64_MIN)) janet_panic("INT64_MIN divided by -1"); \
|
||||
*box oper##= value; \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
static Janet cfun_it_s64_divf(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||
int64_t op1 = janet_unwrap_s64(argv[0]);
|
||||
int64_t op2 = janet_unwrap_s64(argv[1]);
|
||||
if (op2 == 0) janet_panic("division by zero");
|
||||
int64_t x = op1 / op2;
|
||||
*box = x - (((op1 ^ op2) < 0) && (x * op2 != op1));
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
static Janet cfun_it_s64_divfi(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||
int64_t op2 = janet_unwrap_s64(argv[0]);
|
||||
int64_t op1 = janet_unwrap_s64(argv[1]);
|
||||
if (op2 == 0) janet_panic("division by zero");
|
||||
int64_t x = op1 / op2;
|
||||
*box = x - (((op1 ^ op2) < 0) && (x * op2 != op1));
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
static Janet cfun_it_s64_mod(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||
int64_t op1 = janet_unwrap_s64(argv[0]);
|
||||
int64_t op2 = janet_unwrap_s64(argv[1]);
|
||||
if (op2 == 0) {
|
||||
*box = op1;
|
||||
} else {
|
||||
int64_t x = op1 % op2;
|
||||
*box = (((op1 ^ op2) < 0) && (x != 0)) ? x + op2 : x;
|
||||
}
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
static Janet cfun_it_s64_modi(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||
int64_t op2 = janet_unwrap_s64(argv[0]);
|
||||
int64_t op1 = janet_unwrap_s64(argv[1]);
|
||||
if (op2 == 0) {
|
||||
*box = op1;
|
||||
} else {
|
||||
int64_t x = op1 % op2;
|
||||
*box = (((op1 ^ op2) < 0) && (x != 0)) ? x + op2 : x;
|
||||
}
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
OPMETHOD(int64_t, s64, add, +)
|
||||
OPMETHOD(int64_t, s64, sub, -)
|
||||
OPMETHODINVERT(int64_t, s64, sub, -)
|
||||
OPMETHOD(int64_t, s64, mul, *)
|
||||
DIVMETHOD_SIGNED(int64_t, s64, div, /)
|
||||
DIVMETHOD_SIGNED(int64_t, s64, rem, %)
|
||||
DIVMETHODINVERT_SIGNED(int64_t, s64, div, /)
|
||||
DIVMETHODINVERT_SIGNED(int64_t, s64, rem, %)
|
||||
OPMETHOD(int64_t, s64, and, &)
|
||||
OPMETHOD(int64_t, s64, or, |)
|
||||
OPMETHOD(int64_t, s64, xor, ^)
|
||||
UNARYMETHOD(int64_t, s64, not, ~)
|
||||
OPMETHOD(int64_t, s64, lshift, <<)
|
||||
OPMETHOD(int64_t, s64, rshift, >>)
|
||||
OPMETHOD(uint64_t, u64, add, +)
|
||||
OPMETHOD(uint64_t, u64, sub, -)
|
||||
OPMETHODINVERT(uint64_t, u64, sub, -)
|
||||
OPMETHOD(uint64_t, u64, mul, *)
|
||||
DIVMETHOD(uint64_t, u64, div, /)
|
||||
DIVMETHOD(uint64_t, u64, rem, %)
|
||||
DIVMETHOD(uint64_t, u64, mod, %)
|
||||
DIVMETHODINVERT(uint64_t, u64, div, /)
|
||||
DIVMETHODINVERT(uint64_t, u64, rem, %)
|
||||
DIVMETHODINVERT(uint64_t, u64, mod, %)
|
||||
OPMETHOD(uint64_t, u64, and, &)
|
||||
OPMETHOD(uint64_t, u64, or, |)
|
||||
OPMETHOD(uint64_t, u64, xor, ^)
|
||||
UNARYMETHOD(uint64_t, u64, not, ~)
|
||||
OPMETHOD(uint64_t, u64, lshift, <<)
|
||||
OPMETHOD(uint64_t, u64, rshift, >>)
|
||||
|
||||
#undef OPMETHOD
|
||||
#undef DIVMETHOD
|
||||
#undef DIVMETHOD_SIGNED
|
||||
#undef COMPMETHOD
|
||||
|
||||
static JanetMethod it_s64_methods[] = {
|
||||
{"+", cfun_it_s64_add},
|
||||
{"r+", cfun_it_s64_add},
|
||||
{"-", cfun_it_s64_sub},
|
||||
{"r-", cfun_it_s64_subi},
|
||||
{"*", cfun_it_s64_mul},
|
||||
{"r*", cfun_it_s64_mul},
|
||||
{"/", cfun_it_s64_div},
|
||||
{"r/", cfun_it_s64_divi},
|
||||
{"div", cfun_it_s64_divf},
|
||||
{"rdiv", cfun_it_s64_divfi},
|
||||
{"mod", cfun_it_s64_mod},
|
||||
{"rmod", cfun_it_s64_modi},
|
||||
{"%", cfun_it_s64_rem},
|
||||
{"r%", cfun_it_s64_remi},
|
||||
{"&", cfun_it_s64_and},
|
||||
{"r&", cfun_it_s64_and},
|
||||
{"|", cfun_it_s64_or},
|
||||
{"r|", cfun_it_s64_or},
|
||||
{"^", cfun_it_s64_xor},
|
||||
{"r^", cfun_it_s64_xor},
|
||||
{"~", cfun_it_s64_not},
|
||||
{"<<", cfun_it_s64_lshift},
|
||||
{">>", cfun_it_s64_rshift},
|
||||
{"compare", cfun_it_s64_compare},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static JanetMethod it_u64_methods[] = {
|
||||
{"+", cfun_it_u64_add},
|
||||
{"r+", cfun_it_u64_add},
|
||||
{"-", cfun_it_u64_sub},
|
||||
{"r-", cfun_it_u64_subi},
|
||||
{"*", cfun_it_u64_mul},
|
||||
{"r*", cfun_it_u64_mul},
|
||||
{"/", cfun_it_u64_div},
|
||||
{"r/", cfun_it_u64_divi},
|
||||
{"div", cfun_it_u64_div},
|
||||
{"rdiv", cfun_it_u64_divi},
|
||||
{"mod", cfun_it_u64_mod},
|
||||
{"rmod", cfun_it_u64_modi},
|
||||
{"%", cfun_it_u64_rem},
|
||||
{"r%", cfun_it_u64_remi},
|
||||
{"&", cfun_it_u64_and},
|
||||
{"r&", cfun_it_u64_and},
|
||||
{"|", cfun_it_u64_or},
|
||||
{"r|", cfun_it_u64_or},
|
||||
{"^", cfun_it_u64_xor},
|
||||
{"r^", cfun_it_u64_xor},
|
||||
{"~", cfun_it_u64_not},
|
||||
{"<<", cfun_it_u64_lshift},
|
||||
{">>", cfun_it_u64_rshift},
|
||||
{"compare", cfun_it_u64_compare},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static Janet janet_int64_next(void *p, Janet key) {
|
||||
(void) p;
|
||||
return janet_nextmethod(it_s64_methods, key);
|
||||
}
|
||||
|
||||
static Janet janet_uint64_next(void *p, Janet key) {
|
||||
(void) p;
|
||||
return janet_nextmethod(it_u64_methods, key);
|
||||
}
|
||||
|
||||
static int it_s64_get(void *p, Janet key, Janet *out) {
|
||||
(void) p;
|
||||
if (!janet_checktype(key, JANET_KEYWORD))
|
||||
return 0;
|
||||
return janet_getmethod(janet_unwrap_keyword(key), it_s64_methods, out);
|
||||
}
|
||||
|
||||
static int it_u64_get(void *p, Janet key, Janet *out) {
|
||||
(void) p;
|
||||
if (!janet_checktype(key, JANET_KEYWORD))
|
||||
return 0;
|
||||
return janet_getmethod(janet_unwrap_keyword(key), it_u64_methods, out);
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_inttypes(JanetTable *env) {
|
||||
JanetRegExt it_cfuns[] = {
|
||||
JANET_CORE_REG("int/s64", cfun_it_s64_new),
|
||||
JANET_CORE_REG("int/u64", cfun_it_u64_new),
|
||||
JANET_CORE_REG("int/to-number", cfun_to_number),
|
||||
JANET_CORE_REG("int/to-bytes", cfun_to_bytes),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, it_cfuns);
|
||||
janet_register_abstract_type(&janet_s64_type);
|
||||
janet_register_abstract_type(&janet_u64_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
838
src/core/io.c
838
src/core/io.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,146 +20,151 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Compiler feature test macros for things */
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "util.h"
|
||||
#ifndef JANET_WINDOWS
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define IO_WRITE 1
|
||||
#define IO_READ 2
|
||||
#define IO_APPEND 4
|
||||
#define IO_UPDATE 8
|
||||
#define IO_NOT_CLOSEABLE 16
|
||||
#define IO_CLOSED 32
|
||||
#define IO_BINARY 64
|
||||
#define IO_SERIALIZABLE 128
|
||||
#define IO_PIPED 256
|
||||
|
||||
typedef struct IOFile IOFile;
|
||||
struct IOFile {
|
||||
FILE *file;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static int cfun_io_gc(void *p, size_t len);
|
||||
static Janet io_file_get(void *p, Janet);
|
||||
static int io_file_get(void *p, Janet key, Janet *out);
|
||||
static void io_file_marshal(void *p, JanetMarshalContext *ctx);
|
||||
static void *io_file_unmarshal(JanetMarshalContext *ctx);
|
||||
static Janet io_file_next(void *p, Janet key);
|
||||
|
||||
JanetAbstractType cfun_io_filetype = {
|
||||
const JanetAbstractType janet_file_type = {
|
||||
"core/file",
|
||||
cfun_io_gc,
|
||||
NULL,
|
||||
io_file_get,
|
||||
NULL
|
||||
NULL,
|
||||
io_file_marshal,
|
||||
io_file_unmarshal,
|
||||
NULL, /* tostring */
|
||||
NULL, /* compare */
|
||||
NULL, /* hash */
|
||||
io_file_next,
|
||||
JANET_ATEND_NEXT
|
||||
};
|
||||
|
||||
/* Check arguments to fopen */
|
||||
static int checkflags(const uint8_t *str) {
|
||||
int flags = 0;
|
||||
static int32_t checkflags(const uint8_t *str) {
|
||||
int32_t flags = 0;
|
||||
int32_t i;
|
||||
int32_t len = janet_string_length(str);
|
||||
if (!len || len > 3)
|
||||
janet_panic("file mode must have a length between 1 and 3");
|
||||
if (!len || len > 10)
|
||||
janet_panic("file mode must have a length between 1 and 10");
|
||||
switch (*str) {
|
||||
default:
|
||||
janet_panicf("invalid flag %c, expected w, a, or r", *str);
|
||||
break;
|
||||
case 'w':
|
||||
flags |= IO_WRITE;
|
||||
flags |= JANET_FILE_WRITE;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
case 'a':
|
||||
flags |= IO_APPEND;
|
||||
flags |= JANET_FILE_APPEND;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS);
|
||||
break;
|
||||
case 'r':
|
||||
flags |= IO_READ;
|
||||
flags |= JANET_FILE_READ;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
break;
|
||||
}
|
||||
for (i = 1; i < len; i++) {
|
||||
switch (str[i]) {
|
||||
default:
|
||||
janet_panicf("invalid flag %c, expected + or b", str[i]);
|
||||
janet_panicf("invalid flag %c, expected +, b, or n", str[i]);
|
||||
break;
|
||||
case '+':
|
||||
if (flags & IO_UPDATE) return -1;
|
||||
flags |= IO_UPDATE;
|
||||
if (flags & JANET_FILE_UPDATE) return -1;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
flags |= JANET_FILE_UPDATE;
|
||||
break;
|
||||
case 'b':
|
||||
if (flags & IO_BINARY) return -1;
|
||||
flags |= IO_BINARY;
|
||||
if (flags & JANET_FILE_BINARY) return -1;
|
||||
flags |= JANET_FILE_BINARY;
|
||||
break;
|
||||
case 'n':
|
||||
if (flags & JANET_FILE_NONIL) return -1;
|
||||
flags |= JANET_FILE_NONIL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static Janet makef(FILE *f, int flags) {
|
||||
IOFile *iof = (IOFile *) janet_abstract(&cfun_io_filetype, sizeof(IOFile));
|
||||
static void *makef(FILE *f, int32_t flags) {
|
||||
JanetFile *iof = (JanetFile *) janet_abstract(&janet_file_type, sizeof(JanetFile));
|
||||
iof->file = f;
|
||||
iof->flags = flags;
|
||||
return janet_wrap_abstract(iof);
|
||||
#ifndef JANET_WINDOWS
|
||||
/* While we would like fopen to set cloexec by default (like O_CLOEXEC) with the e flag, that is
|
||||
* not standard. */
|
||||
if (!(flags & JANET_FILE_NOT_CLOSEABLE))
|
||||
fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
return iof;
|
||||
}
|
||||
|
||||
/* Open a process */
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static Janet cfun_io_popen(int32_t argc, Janet *argv) {
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
janet_panic("not implemented on this platform");
|
||||
return janet_wrap_nil();
|
||||
JANET_CORE_FN(cfun_io_temp,
|
||||
"(file/temp)",
|
||||
"Open an anonymous temporary file that is removed on close. "
|
||||
"Raises an error on failure.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_TEMP);
|
||||
(void)argv;
|
||||
janet_fixarity(argc, 0);
|
||||
// XXX use mkostemp when we can to avoid CLOEXEC race.
|
||||
FILE *tmp = tmpfile();
|
||||
if (!tmp)
|
||||
janet_panicf("unable to create temporary file - %s", strerror(errno));
|
||||
return janet_makefile(tmp, JANET_FILE_WRITE | JANET_FILE_READ | JANET_FILE_BINARY);
|
||||
}
|
||||
#else
|
||||
static Janet cfun_io_popen(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
const uint8_t *fname = janet_getstring(argv, 0);
|
||||
const uint8_t *fmode = NULL;
|
||||
int flags;
|
||||
if (argc == 2) {
|
||||
fmode = janet_getkeyword(argv, 1);
|
||||
if (janet_string_length(fmode) != 1 ||
|
||||
!(fmode[0] == 'r' || fmode[0] == 'w')) {
|
||||
janet_panicf("invalid file mode :%S, expected :r or :w", fmode);
|
||||
}
|
||||
flags = IO_PIPED | (fmode[0] == 'r' ? IO_READ : IO_WRITE);
|
||||
} else {
|
||||
fmode = (const uint8_t *)"r";
|
||||
flags = IO_PIPED | IO_READ;
|
||||
}
|
||||
#ifdef JANET_WINDOWS
|
||||
#define popen _popen
|
||||
#endif
|
||||
FILE *f = popen((const char *)fname, (const char *)fmode);
|
||||
if (!f) {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
return makef(f, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_io_fopen,
|
||||
"(file/open path &opt mode)",
|
||||
"Open a file. `path` is an absolute or relative path, and "
|
||||
"`mode` is a set of flags indicating the mode to open the file in. "
|
||||
"`mode` is a keyword where each character represents a flag. If the file "
|
||||
"cannot be opened, returns nil, otherwise returns the new file handle. "
|
||||
"Mode flags:\n\n"
|
||||
"* r - allow reading from the file\n\n"
|
||||
"* w - allow writing to the file\n\n"
|
||||
"* a - append to the file\n\n"
|
||||
"Following one of the initial flags, 0 or more of the following flags can be appended:\n\n"
|
||||
"* b - open the file in binary mode (rather than text mode)\n\n"
|
||||
"* + - append to the file instead of overwriting it\n\n"
|
||||
"* n - error if the file cannot be opened instead of returning nil") {
|
||||
janet_arity(argc, 1, 2);
|
||||
const uint8_t *fname = janet_getstring(argv, 0);
|
||||
const uint8_t *fmode;
|
||||
int flags;
|
||||
int32_t flags;
|
||||
if (argc == 2) {
|
||||
fmode = janet_getkeyword(argv, 1);
|
||||
flags = checkflags(fmode);
|
||||
} else {
|
||||
fmode = (const uint8_t *)"r";
|
||||
flags = IO_READ;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
flags = JANET_FILE_READ;
|
||||
}
|
||||
FILE *f = fopen((const char *)fname, (const char *)fmode);
|
||||
return f ? makef(f, flags) : janet_wrap_nil();
|
||||
return f ? janet_makefile(f, flags)
|
||||
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil())
|
||||
: janet_wrap_nil();
|
||||
}
|
||||
|
||||
/* Read up to n bytes into buffer. Return error string if error. */
|
||||
static void read_chunk(IOFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
||||
if (!(iof->flags & (IO_READ | IO_UPDATE)))
|
||||
/* Read up to n bytes into buffer. */
|
||||
static void read_chunk(JanetFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
||||
if (!(iof->flags & (JANET_FILE_READ | JANET_FILE_UPDATE)))
|
||||
janet_panic("file is not readable");
|
||||
janet_buffer_extra(buffer, nBytesMax);
|
||||
size_t ntoread = nBytesMax;
|
||||
@@ -170,34 +175,36 @@ static void read_chunk(IOFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
||||
}
|
||||
|
||||
/* Read a certain number of bytes into memory */
|
||||
static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_io_fread,
|
||||
"(file/read f what &opt buf)",
|
||||
"Read a number of bytes from a file `f` into a buffer. A buffer `buf` can "
|
||||
"be provided as an optional third argument, otherwise a new buffer "
|
||||
"is created. `what` can either be an integer or a keyword. Returns the "
|
||||
"buffer with file contents. "
|
||||
"Values for `what`:\n\n"
|
||||
"* :all - read the whole file\n\n"
|
||||
"* :line - read up to and including the next newline character\n\n"
|
||||
"* n (integer) - read up to n bytes from the file") {
|
||||
janet_arity(argc, 2, 3);
|
||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
||||
if (iof->flags & IO_CLOSED) janet_panic("file is closed");
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED) janet_panic("file is closed");
|
||||
JanetBuffer *buffer;
|
||||
if (argc == 2) {
|
||||
buffer = janet_buffer(0);
|
||||
} else {
|
||||
buffer = janet_getbuffer(argv, 2);
|
||||
}
|
||||
int32_t bufstart = buffer->count;
|
||||
if (janet_checktype(argv[1], JANET_KEYWORD)) {
|
||||
const uint8_t *sym = janet_unwrap_keyword(argv[1]);
|
||||
if (!janet_cstrcmp(sym, "all")) {
|
||||
/* Read whole file */
|
||||
int status = fseek(iof->file, 0, SEEK_SET);
|
||||
if (status) {
|
||||
/* backwards fseek did not work (stream like popen) */
|
||||
int32_t sizeBefore;
|
||||
do {
|
||||
sizeBefore = buffer->count;
|
||||
read_chunk(iof, buffer, 1024);
|
||||
} while (sizeBefore < buffer->count);
|
||||
} else {
|
||||
fseek(iof->file, 0, SEEK_END);
|
||||
long fsize = ftell(iof->file);
|
||||
fseek(iof->file, 0, SEEK_SET);
|
||||
read_chunk(iof, buffer, (int32_t) fsize);
|
||||
}
|
||||
int32_t sizeBefore;
|
||||
do {
|
||||
sizeBefore = buffer->count;
|
||||
read_chunk(iof, buffer, 4096);
|
||||
} while (sizeBefore < buffer->count);
|
||||
/* Never return nil for :all */
|
||||
return janet_wrap_buffer(buffer);
|
||||
} else if (!janet_cstrcmp(sym, "line")) {
|
||||
for (;;) {
|
||||
int x = fgetc(iof->file);
|
||||
@@ -212,16 +219,20 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||
if (len < 0) janet_panic("expected positive integer");
|
||||
read_chunk(iof, buffer, len);
|
||||
}
|
||||
if (bufstart == buffer->count) return janet_wrap_nil();
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
/* Write bytes to a file */
|
||||
static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_io_fwrite,
|
||||
"(file/write f bytes)",
|
||||
"Writes to a file. 'bytes' must be string, buffer, or symbol. Returns the "
|
||||
"file.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
||||
if (iof->flags & IO_CLOSED)
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
if (!(iof->flags & (IO_WRITE | IO_APPEND | IO_UPDATE)))
|
||||
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
|
||||
janet_panic("file is not writeable");
|
||||
int32_t i;
|
||||
/* Verify all arguments before writing to file */
|
||||
@@ -238,54 +249,83 @@ static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
/* Flush the bytes in the file */
|
||||
static Janet cfun_io_fflush(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
||||
if (iof->flags & IO_CLOSED)
|
||||
static void io_assert_writeable(JanetFile *iof) {
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
if (!(iof->flags & (IO_WRITE | IO_APPEND | IO_UPDATE)))
|
||||
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
|
||||
janet_panic("file is not writeable");
|
||||
}
|
||||
|
||||
/* Flush the bytes in the file */
|
||||
JANET_CORE_FN(cfun_io_fflush,
|
||||
"(file/flush f)",
|
||||
"Flush any buffered bytes to the file system. In most files, writes are "
|
||||
"buffered for efficiency reasons. Returns the file handle.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
io_assert_writeable(iof);
|
||||
if (fflush(iof->file))
|
||||
janet_panic("could not flush file");
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
/* Cleanup a file */
|
||||
static int cfun_io_gc(void *p, size_t len) {
|
||||
(void) len;
|
||||
IOFile *iof = (IOFile *)p;
|
||||
if (!(iof->flags & (IO_NOT_CLOSEABLE | IO_CLOSED))) {
|
||||
return fclose(iof->file);
|
||||
#ifdef JANET_WINDOWS
|
||||
#define WEXITSTATUS(x) x
|
||||
#endif
|
||||
|
||||
/* For closing files from C API */
|
||||
int janet_file_close(JanetFile *file) {
|
||||
int ret = 0;
|
||||
if (!(file->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
|
||||
ret = fclose(file->file);
|
||||
file->flags |= JANET_FILE_CLOSED;
|
||||
file->file = NULL; /* NULL derefence is easier to debug then other problems */
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup a file */
|
||||
static int cfun_io_gc(void *p, size_t len) {
|
||||
(void) len;
|
||||
JanetFile *iof = (JanetFile *)p;
|
||||
janet_file_close(iof);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close a file */
|
||||
static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_io_fclose,
|
||||
"(file/close f)",
|
||||
"Close a file and release all related resources. When you are "
|
||||
"done reading a file, close it to prevent a resource leak and let "
|
||||
"other processes read the file.") {
|
||||
janet_fixarity(argc, 1);
|
||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
||||
if (iof->flags & IO_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
if (iof->flags & (IO_NOT_CLOSEABLE))
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
return janet_wrap_nil();
|
||||
if (iof->flags & (JANET_FILE_NOT_CLOSEABLE))
|
||||
janet_panic("file not closable");
|
||||
if (iof->flags & IO_PIPED) {
|
||||
#ifdef JANET_WINDOWS
|
||||
#define pclose _pclose
|
||||
#endif
|
||||
if (pclose(iof->file)) janet_panic("could not close file");
|
||||
} else {
|
||||
if (fclose(iof->file)) janet_panic("could not close file");
|
||||
if (fclose(iof->file)) {
|
||||
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
|
||||
janet_panic("could not close file");
|
||||
}
|
||||
iof->flags |= IO_CLOSED;
|
||||
return argv[0];
|
||||
iof->flags |= JANET_FILE_CLOSED;
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
/* Seek a file */
|
||||
static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_io_fseek,
|
||||
"(file/seek f &opt whence n)",
|
||||
"Jump to a relative location in the file `f`. `whence` must be one of:\n\n"
|
||||
"* :cur - jump relative to the current file location\n\n"
|
||||
"* :set - jump relative to the beginning of the file\n\n"
|
||||
"* :end - jump relative to the end of the file\n\n"
|
||||
"By default, `whence` is :cur. Optionally a value `n` may be passed "
|
||||
"for the relative number of bytes to seek in the file. `n` may be a real "
|
||||
"number to handle large files of more than 4GB. Returns the file handle.") {
|
||||
janet_arity(argc, 2, 3);
|
||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
||||
if (iof->flags & IO_CLOSED)
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
long int offset = 0;
|
||||
int whence = SEEK_CUR;
|
||||
@@ -308,104 +348,470 @@ static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_ftell,
|
||||
"(file/tell f)",
|
||||
"Get the current value of the file position for file `f`.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
long pos = ftell(iof->file);
|
||||
if (pos == -1) janet_panic("error getting position in file");
|
||||
return janet_wrap_number((double)pos);
|
||||
}
|
||||
|
||||
static JanetMethod io_file_methods[] = {
|
||||
{"close", cfun_io_fclose},
|
||||
{"read", cfun_io_fread},
|
||||
{"write", cfun_io_fwrite},
|
||||
{"flush", cfun_io_fflush},
|
||||
{"read", cfun_io_fread},
|
||||
{"seek", cfun_io_fseek},
|
||||
{"tell", cfun_io_ftell},
|
||||
{"write", cfun_io_fwrite},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static Janet io_file_get(void *p, Janet key) {
|
||||
static int io_file_get(void *p, Janet key, Janet *out) {
|
||||
(void) p;
|
||||
if (!janet_checktype(key, JANET_KEYWORD))
|
||||
janet_panicf("expected keyword, got %v", key);
|
||||
return janet_getmethod(janet_unwrap_keyword(key), io_file_methods);
|
||||
return 0;
|
||||
return janet_getmethod(janet_unwrap_keyword(key), io_file_methods, out);
|
||||
}
|
||||
|
||||
static const JanetReg io_cfuns[] = {
|
||||
{
|
||||
"file/open", cfun_io_fopen,
|
||||
JDOC("(file/open path [,mode])\n\n"
|
||||
"Open a file. path is an absolute or relative path, and "
|
||||
"mode is a set of flags indicating the mode to open the file in. "
|
||||
"mode is a keyword where each character represents a flag. If the file "
|
||||
"cannot be opened, returns nil, otherwise returns the new file handle. "
|
||||
"Mode flags:\n\n"
|
||||
"\tr - allow reading from the file\n"
|
||||
"\tw - allow writing to the file\n"
|
||||
"\ta - append to the file\n"
|
||||
"\tb - open the file in binary mode (rather than text mode)\n"
|
||||
"\t+ - append to the file instead of overwriting it")
|
||||
},
|
||||
{
|
||||
"file/close", cfun_io_fclose,
|
||||
JDOC("(file/close f)\n\n"
|
||||
"Close a file and release all related resources. When you are "
|
||||
"done reading a file, close it to prevent a resource leak and let "
|
||||
"other processes read the file.")
|
||||
},
|
||||
{
|
||||
"file/read", cfun_io_fread,
|
||||
JDOC("(file/read f what [,buf])\n\n"
|
||||
"Read a number of bytes from a file into a buffer. A buffer can "
|
||||
"be provided as an optional fourth argument, otherwise a new buffer "
|
||||
"is created. 'what' can either be an integer or a keyword. Returns the "
|
||||
"buffer with file contents. "
|
||||
"Values for 'what':\n\n"
|
||||
"\t:all - read the whole file\n"
|
||||
"\t:line - read up to and including the next newline character\n"
|
||||
"\tn (integer) - read up to n bytes from the file")
|
||||
},
|
||||
{
|
||||
"file/write", cfun_io_fwrite,
|
||||
JDOC("(file/write f bytes)\n\n"
|
||||
"Writes to a file. 'bytes' must be string, buffer, or symbol. Returns the "
|
||||
"file.")
|
||||
},
|
||||
{
|
||||
"file/flush", cfun_io_fflush,
|
||||
JDOC("(file/flush f)\n\n"
|
||||
"Flush any buffered bytes to the file system. In most files, writes are "
|
||||
"buffered for efficiency reasons. Returns the file handle.")
|
||||
},
|
||||
{
|
||||
"file/seek", cfun_io_fseek,
|
||||
JDOC("(file/seek f [,whence [,n]])\n\n"
|
||||
"Jump to a relative location in the file. 'whence' must be one of\n\n"
|
||||
"\t:cur - jump relative to the current file location\n"
|
||||
"\t:set - jump relative to the beginning of the file\n"
|
||||
"\t:end - jump relative to the end of the file\n\n"
|
||||
"By default, 'whence' is :cur. Optionally a value n may be passed "
|
||||
"for the relative number of bytes to seek in the file. n may be a real "
|
||||
"number to handle large files of more the 4GB. Returns the file handle.")
|
||||
},
|
||||
{
|
||||
"file/popen", cfun_io_popen,
|
||||
JDOC("(file/popen path [,mode])\n\n"
|
||||
"Open a file that is backed by a process. The file must be opened in either "
|
||||
"the :r (read) or the :w (write) mode. In :r mode, the stdout of the "
|
||||
"process can be read from the file. In :w mode, the stdin of the process "
|
||||
"can be written to. Returns the new file.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
static Janet io_file_next(void *p, Janet key) {
|
||||
(void) p;
|
||||
return janet_nextmethod(io_file_methods, key);
|
||||
}
|
||||
|
||||
static void io_file_marshal(void *p, JanetMarshalContext *ctx) {
|
||||
JanetFile *iof = (JanetFile *)p;
|
||||
if (ctx->flags & JANET_MARSHAL_UNSAFE) {
|
||||
janet_marshal_abstract(ctx, p);
|
||||
#ifdef JANET_WINDOWS
|
||||
janet_marshal_int(ctx, _fileno(iof->file));
|
||||
#else
|
||||
janet_marshal_int(ctx, fileno(iof->file));
|
||||
#endif
|
||||
janet_marshal_int(ctx, iof->flags);
|
||||
} else {
|
||||
janet_panic("cannot marshal file in safe mode");
|
||||
}
|
||||
}
|
||||
|
||||
static void *io_file_unmarshal(JanetMarshalContext *ctx) {
|
||||
if (ctx->flags & JANET_MARSHAL_UNSAFE) {
|
||||
JanetFile *iof = janet_unmarshal_abstract(ctx, sizeof(JanetFile));
|
||||
int32_t fd = janet_unmarshal_int(ctx);
|
||||
int32_t flags = janet_unmarshal_int(ctx);
|
||||
char fmt[4] = {0};
|
||||
int index = 0;
|
||||
if (flags & JANET_FILE_READ) fmt[index++] = 'r';
|
||||
if (flags & JANET_FILE_APPEND) {
|
||||
fmt[index++] = 'a';
|
||||
} else if (flags & JANET_FILE_WRITE) {
|
||||
fmt[index++] = 'w';
|
||||
}
|
||||
#ifdef JANET_WINDOWS
|
||||
iof->file = _fdopen(fd, fmt);
|
||||
#else
|
||||
iof->file = fdopen(fd, fmt);
|
||||
#endif
|
||||
if (iof->file == NULL) {
|
||||
iof->flags = JANET_FILE_CLOSED;
|
||||
} else {
|
||||
iof->flags = flags;
|
||||
}
|
||||
return iof;
|
||||
} else {
|
||||
janet_panic("cannot unmarshal file in safe mode");
|
||||
}
|
||||
}
|
||||
|
||||
FILE *janet_dynfile(const char *name, FILE *def) {
|
||||
Janet x = janet_dyn(name);
|
||||
if (!janet_checktype(x, JANET_ABSTRACT)) return def;
|
||||
void *abstract = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abstract) != &janet_file_type) return def;
|
||||
JanetFile *iofile = abstract;
|
||||
return iofile->file;
|
||||
}
|
||||
|
||||
static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
|
||||
FILE *dflt_file, int32_t offset, Janet x) {
|
||||
FILE *f;
|
||||
switch (janet_type(x)) {
|
||||
default:
|
||||
janet_panicf("cannot print to %v", x);
|
||||
case JANET_BUFFER: {
|
||||
/* Special case buffer */
|
||||
JanetBuffer *buf = janet_unwrap_buffer(x);
|
||||
for (int32_t i = offset; i < argc; ++i) {
|
||||
janet_to_string_b(buf, argv[i]);
|
||||
}
|
||||
if (newline)
|
||||
janet_buffer_push_u8(buf, '\n');
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
case JANET_FUNCTION: {
|
||||
/* Special case function */
|
||||
JanetFunction *fun = janet_unwrap_function(x);
|
||||
JanetBuffer *buf = janet_buffer(0);
|
||||
for (int32_t i = offset; i < argc; ++i) {
|
||||
janet_to_string_b(buf, argv[i]);
|
||||
}
|
||||
if (newline)
|
||||
janet_buffer_push_u8(buf, '\n');
|
||||
Janet args[1] = { janet_wrap_buffer(buf) };
|
||||
janet_call(fun, 1, args);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
case JANET_NIL:
|
||||
f = dflt_file;
|
||||
if (f == NULL) janet_panic("cannot print to nil");
|
||||
break;
|
||||
case JANET_ABSTRACT: {
|
||||
void *abstract = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abstract) != &janet_file_type)
|
||||
return janet_wrap_nil();
|
||||
JanetFile *iofile = abstract;
|
||||
io_assert_writeable(iofile);
|
||||
f = iofile->file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int32_t i = offset; i < argc; ++i) {
|
||||
int32_t len;
|
||||
const uint8_t *vstr;
|
||||
if (janet_checktype(argv[i], JANET_BUFFER)) {
|
||||
JanetBuffer *b = janet_unwrap_buffer(argv[i]);
|
||||
vstr = b->data;
|
||||
len = b->count;
|
||||
} else {
|
||||
vstr = janet_to_string(argv[i]);
|
||||
len = janet_string_length(vstr);
|
||||
}
|
||||
if (len) {
|
||||
if (1 != fwrite(vstr, len, 1, f)) {
|
||||
if (f == dflt_file) {
|
||||
janet_panicf("cannot print %d bytes", len);
|
||||
} else {
|
||||
janet_panicf("cannot print %d bytes to %v", len, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newline)
|
||||
putc('\n', f);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
||||
int newline, const char *name, FILE *dflt_file) {
|
||||
Janet x = janet_dyn(name);
|
||||
return cfun_io_print_impl_x(argc, argv, newline, dflt_file, 0, x);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_print,
|
||||
"(print & xs)",
|
||||
"Print values to the console (standard out). Value are converted "
|
||||
"to strings if they are not already. After printing all values, a "
|
||||
"newline character is printed. Use the value of `(dyn :out stdout)` to determine "
|
||||
"what to push characters to. Expects `(dyn :out stdout)` to be either a core/file or "
|
||||
"a buffer. Returns nil.") {
|
||||
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_prin,
|
||||
"(prin & xs)",
|
||||
"Same as `print`, but does not add trailing newline.") {
|
||||
return cfun_io_print_impl(argc, argv, 0, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprint,
|
||||
"(eprint & xs)",
|
||||
"Same as `print`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
|
||||
return cfun_io_print_impl(argc, argv, 1, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprin,
|
||||
"(eprin & xs)",
|
||||
"Same as `prin`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
|
||||
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_xprint,
|
||||
"(xprint to & xs)",
|
||||
"Print to a file or other value explicitly (no dynamic bindings) with a trailing "
|
||||
"newline character. The value to print "
|
||||
"to is the first argument, and is otherwise the same as `print`. Returns nil.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
return cfun_io_print_impl_x(argc, argv, 1, NULL, 1, argv[0]);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_xprin,
|
||||
"(xprin to & xs)",
|
||||
"Print to a file or other value explicitly (no dynamic bindings). The value to print "
|
||||
"to is the first argument, and is otherwise the same as `prin`. Returns nil.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
return cfun_io_print_impl_x(argc, argv, 0, NULL, 1, argv[0]);
|
||||
}
|
||||
|
||||
static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
|
||||
FILE *dflt_file, int32_t offset, Janet x) {
|
||||
FILE *f;
|
||||
const char *fmt = janet_getcstring(argv, offset);
|
||||
switch (janet_type(x)) {
|
||||
default:
|
||||
janet_panicf("cannot print to %v", x);
|
||||
case JANET_BUFFER: {
|
||||
/* Special case buffer */
|
||||
JanetBuffer *buf = janet_unwrap_buffer(x);
|
||||
janet_buffer_format(buf, fmt, offset, argc, argv);
|
||||
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
case JANET_FUNCTION: {
|
||||
/* Special case function */
|
||||
JanetFunction *fun = janet_unwrap_function(x);
|
||||
JanetBuffer *buf = janet_buffer(0);
|
||||
janet_buffer_format(buf, fmt, offset, argc, argv);
|
||||
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||
Janet args[1] = { janet_wrap_buffer(buf) };
|
||||
janet_call(fun, 1, args);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
case JANET_NIL:
|
||||
f = dflt_file;
|
||||
if (f == NULL) janet_panic("cannot print to nil");
|
||||
break;
|
||||
case JANET_ABSTRACT: {
|
||||
void *abstract = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abstract) != &janet_file_type)
|
||||
return janet_wrap_nil();
|
||||
JanetFile *iofile = abstract;
|
||||
if (iofile->flags & JANET_FILE_CLOSED) {
|
||||
janet_panic("cannot print to closed file");
|
||||
}
|
||||
io_assert_writeable(iofile);
|
||||
f = iofile->file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
JanetBuffer *buf = janet_buffer(10);
|
||||
janet_buffer_format(buf, fmt, offset, argc, argv);
|
||||
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||
if (buf->count) {
|
||||
if (1 != fwrite(buf->data, buf->count, 1, f)) {
|
||||
janet_panicf("could not print %d bytes to file", buf->count);
|
||||
}
|
||||
}
|
||||
/* Clear buffer to make things easier for GC */
|
||||
buf->count = 0;
|
||||
buf->capacity = 0;
|
||||
janet_free(buf->data);
|
||||
buf->data = NULL;
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
||||
const char *name, FILE *dflt_file) {
|
||||
janet_arity(argc, 1, -1);
|
||||
Janet x = janet_dyn(name);
|
||||
return cfun_io_printf_impl_x(argc, argv, newline, dflt_file, 0, x);
|
||||
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_printf,
|
||||
"(printf fmt & xs)",
|
||||
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :out stdout)` with a trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_prinf,
|
||||
"(prinf fmt & xs)",
|
||||
"Like `printf` but with no trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 0, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprintf,
|
||||
"(eprintf fmt & xs)",
|
||||
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :err stderr)` with a trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 1, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprinf,
|
||||
"(eprinf fmt & xs)",
|
||||
"Like `eprintf` but with no trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_xprintf,
|
||||
"(xprintf to fmt & xs)",
|
||||
"Like `printf` but prints to an explicit file or value `to`. Returns nil.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
return cfun_io_printf_impl_x(argc, argv, 1, NULL, 1, argv[0]);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_xprinf,
|
||||
"(xprinf to fmt & xs)",
|
||||
"Like `prinf` but prints to an explicit file or value `to`. Returns nil.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
return cfun_io_printf_impl_x(argc, argv, 0, NULL, 1, argv[0]);
|
||||
}
|
||||
|
||||
static void janet_flusher(const char *name, FILE *dflt_file) {
|
||||
Janet x = janet_dyn(name);
|
||||
switch (janet_type(x)) {
|
||||
default:
|
||||
break;
|
||||
case JANET_NIL:
|
||||
fflush(dflt_file);
|
||||
break;
|
||||
case JANET_ABSTRACT: {
|
||||
void *abstract = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abstract) != &janet_file_type) break;
|
||||
JanetFile *iofile = abstract;
|
||||
fflush(iofile->file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_flush,
|
||||
"(flush)",
|
||||
"Flush `(dyn :out stdout)` if it is a file, otherwise do nothing.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
janet_flusher("out", stdout);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eflush,
|
||||
"(eflush)",
|
||||
"Flush `(dyn :err stderr)` if it is a file, otherwise do nothing.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
janet_flusher("err", stderr);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
Janet x = janet_dyn(name);
|
||||
JanetType xtype = janet_type(x);
|
||||
switch (xtype) {
|
||||
default:
|
||||
/* Other values simply do nothing */
|
||||
break;
|
||||
case JANET_NIL:
|
||||
case JANET_ABSTRACT: {
|
||||
FILE *f = dflt_file;
|
||||
JanetBuffer buffer;
|
||||
int32_t len = 0;
|
||||
while (format[len]) len++;
|
||||
janet_buffer_init(&buffer, len);
|
||||
janet_formatbv(&buffer, format, args);
|
||||
if (xtype == JANET_ABSTRACT) {
|
||||
void *abstract = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abstract) != &janet_file_type)
|
||||
break;
|
||||
JanetFile *iofile = abstract;
|
||||
io_assert_writeable(iofile);
|
||||
f = iofile->file;
|
||||
}
|
||||
fwrite(buffer.data, buffer.count, 1, f);
|
||||
janet_buffer_deinit(&buffer);
|
||||
break;
|
||||
}
|
||||
case JANET_FUNCTION: {
|
||||
JanetFunction *fun = janet_unwrap_function(x);
|
||||
int32_t len = 0;
|
||||
while (format[len]) len++;
|
||||
JanetBuffer *buf = janet_buffer(len);
|
||||
janet_formatbv(buf, format, args);
|
||||
Janet args[1] = { janet_wrap_buffer(buf) };
|
||||
janet_call(fun, 1, args);
|
||||
break;
|
||||
}
|
||||
case JANET_BUFFER:
|
||||
janet_formatbv(janet_unwrap_buffer(x), format, args);
|
||||
break;
|
||||
}
|
||||
va_end(args);
|
||||
return;
|
||||
}
|
||||
|
||||
/* C API */
|
||||
|
||||
JanetFile *janet_getjfile(const Janet *argv, int32_t n) {
|
||||
return janet_getabstract(argv, n, &janet_file_type);
|
||||
}
|
||||
|
||||
FILE *janet_getfile(const Janet *argv, int32_t n, int32_t *flags) {
|
||||
JanetFile *iof = janet_getabstract(argv, n, &janet_file_type);
|
||||
if (NULL != flags) *flags = iof->flags;
|
||||
return iof->file;
|
||||
}
|
||||
|
||||
JanetFile *janet_makejfile(FILE *f, int32_t flags) {
|
||||
return makef(f, flags);
|
||||
}
|
||||
|
||||
Janet janet_makefile(FILE *f, int32_t flags) {
|
||||
return janet_wrap_abstract(makef(f, flags));
|
||||
}
|
||||
|
||||
JanetAbstract janet_checkfile(Janet j) {
|
||||
return janet_checkabstract(j, &janet_file_type);
|
||||
}
|
||||
|
||||
FILE *janet_unwrapfile(Janet j, int32_t *flags) {
|
||||
JanetFile *iof = janet_unwrap_abstract(j);
|
||||
if (NULL != flags) *flags = iof->flags;
|
||||
return iof->file;
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_io(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, io_cfuns);
|
||||
|
||||
JanetRegExt io_cfuns[] = {
|
||||
JANET_CORE_REG("print", cfun_io_print),
|
||||
JANET_CORE_REG("prin", cfun_io_prin),
|
||||
JANET_CORE_REG("printf", cfun_io_printf),
|
||||
JANET_CORE_REG("prinf", cfun_io_prinf),
|
||||
JANET_CORE_REG("eprin", cfun_io_eprin),
|
||||
JANET_CORE_REG("eprint", cfun_io_eprint),
|
||||
JANET_CORE_REG("eprintf", cfun_io_eprintf),
|
||||
JANET_CORE_REG("eprinf", cfun_io_eprinf),
|
||||
JANET_CORE_REG("xprint", cfun_io_xprint),
|
||||
JANET_CORE_REG("xprin", cfun_io_xprin),
|
||||
JANET_CORE_REG("xprintf", cfun_io_xprintf),
|
||||
JANET_CORE_REG("xprinf", cfun_io_xprinf),
|
||||
JANET_CORE_REG("flush", cfun_io_flush),
|
||||
JANET_CORE_REG("eflush", cfun_io_eflush),
|
||||
JANET_CORE_REG("file/temp", cfun_io_temp),
|
||||
JANET_CORE_REG("file/open", cfun_io_fopen),
|
||||
JANET_CORE_REG("file/close", cfun_io_fclose),
|
||||
JANET_CORE_REG("file/read", cfun_io_fread),
|
||||
JANET_CORE_REG("file/write", cfun_io_fwrite),
|
||||
JANET_CORE_REG("file/flush", cfun_io_fflush),
|
||||
JANET_CORE_REG("file/seek", cfun_io_fseek),
|
||||
JANET_CORE_REG("file/tell", cfun_io_ftell),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, io_cfuns);
|
||||
janet_register_abstract_type(&janet_file_type);
|
||||
int default_flags = JANET_FILE_NOT_CLOSEABLE | JANET_FILE_SERIALIZABLE;
|
||||
/* stdout */
|
||||
janet_core_def(env, "stdout",
|
||||
makef(stdout, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE),
|
||||
JDOC("The standard output file."));
|
||||
JANET_CORE_DEF(env, "stdout",
|
||||
janet_makefile(stdout, JANET_FILE_APPEND | default_flags),
|
||||
"The standard output file.");
|
||||
/* stderr */
|
||||
janet_core_def(env, "stderr",
|
||||
makef(stderr, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE),
|
||||
JDOC("The standard error file."));
|
||||
JANET_CORE_DEF(env, "stderr",
|
||||
janet_makefile(stderr, JANET_FILE_APPEND | default_flags),
|
||||
"The standard error file.");
|
||||
/* stdin */
|
||||
janet_core_def(env, "stdin",
|
||||
makef(stdin, IO_READ | IO_NOT_CLOSEABLE | IO_SERIALIZABLE),
|
||||
JDOC("The standard input file."));
|
||||
JANET_CORE_DEF(env, "stdin",
|
||||
janet_makefile(stdin, JANET_FILE_READ | default_flags),
|
||||
"The standard input file.");
|
||||
|
||||
}
|
||||
|
||||
1670
src/core/marsh.c
1670
src/core/marsh.c
File diff suppressed because it is too large
Load Diff
504
src/core/math.c
504
src/core/math.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Calvin Rose
|
||||
* Copyright (c) 2023 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -20,174 +20,406 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet/janet.h>
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static int janet_rng_get(void *p, Janet key, Janet *out);
|
||||
static Janet janet_rng_next(void *p, Janet key);
|
||||
|
||||
static void janet_rng_marshal(void *p, JanetMarshalContext *ctx) {
|
||||
JanetRNG *rng = (JanetRNG *)p;
|
||||
janet_marshal_abstract(ctx, p);
|
||||
janet_marshal_int(ctx, (int32_t) rng->a);
|
||||
janet_marshal_int(ctx, (int32_t) rng->b);
|
||||
janet_marshal_int(ctx, (int32_t) rng->c);
|
||||
janet_marshal_int(ctx, (int32_t) rng->d);
|
||||
janet_marshal_int(ctx, (int32_t) rng->counter);
|
||||
}
|
||||
|
||||
static void *janet_rng_unmarshal(JanetMarshalContext *ctx) {
|
||||
JanetRNG *rng = janet_unmarshal_abstract(ctx, sizeof(JanetRNG));
|
||||
rng->a = (uint32_t) janet_unmarshal_int(ctx);
|
||||
rng->b = (uint32_t) janet_unmarshal_int(ctx);
|
||||
rng->c = (uint32_t) janet_unmarshal_int(ctx);
|
||||
rng->d = (uint32_t) janet_unmarshal_int(ctx);
|
||||
rng->counter = (uint32_t) janet_unmarshal_int(ctx);
|
||||
return rng;
|
||||
}
|
||||
|
||||
const JanetAbstractType janet_rng_type = {
|
||||
"core/rng",
|
||||
NULL,
|
||||
NULL,
|
||||
janet_rng_get,
|
||||
NULL,
|
||||
janet_rng_marshal,
|
||||
janet_rng_unmarshal,
|
||||
NULL, /* tostring */
|
||||
NULL, /* compare */
|
||||
NULL, /* hash */
|
||||
janet_rng_next,
|
||||
JANET_ATEND_NEXT
|
||||
};
|
||||
|
||||
JanetRNG *janet_default_rng(void) {
|
||||
return &janet_vm.rng;
|
||||
}
|
||||
|
||||
void janet_rng_seed(JanetRNG *rng, uint32_t seed) {
|
||||
rng->a = seed;
|
||||
rng->b = 0x97654321u;
|
||||
rng->c = 123871873u;
|
||||
rng->d = 0xf23f56c8u;
|
||||
rng->counter = 0u;
|
||||
/* First several numbers aren't that random. */
|
||||
for (int i = 0; i < 16; i++) janet_rng_u32(rng);
|
||||
}
|
||||
|
||||
void janet_rng_longseed(JanetRNG *rng, const uint8_t *bytes, int32_t len) {
|
||||
uint8_t state[16] = {0};
|
||||
for (int32_t i = 0; i < len; i++)
|
||||
state[i & 0xF] ^= bytes[i];
|
||||
rng->a = state[0] + (state[1] << 8) + (state[2] << 16) + (state[3] << 24);
|
||||
rng->b = state[4] + (state[5] << 8) + (state[6] << 16) + (state[7] << 24);
|
||||
rng->c = state[8] + (state[9] << 8) + (state[10] << 16) + (state[11] << 24);
|
||||
rng->d = state[12] + (state[13] << 8) + (state[14] << 16) + (state[15] << 24);
|
||||
rng->counter = 0u;
|
||||
/* a, b, c, d can't all be 0 */
|
||||
if (rng->a == 0) rng->a = 1u;
|
||||
for (int i = 0; i < 16; i++) janet_rng_u32(rng);
|
||||
}
|
||||
|
||||
uint32_t janet_rng_u32(JanetRNG *rng) {
|
||||
/* Algorithm "xorwow" from p. 5 of Marsaglia, "Xorshift RNGs" */
|
||||
uint32_t t = rng->d;
|
||||
uint32_t const s = rng->a;
|
||||
rng->d = rng->c;
|
||||
rng->c = rng->b;
|
||||
rng->b = s;
|
||||
t ^= t >> 2;
|
||||
t ^= t << 1;
|
||||
t ^= s ^ (s << 4);
|
||||
rng->a = t;
|
||||
rng->counter += 362437;
|
||||
return t + rng->counter;
|
||||
}
|
||||
|
||||
double janet_rng_double(JanetRNG *rng) {
|
||||
uint32_t hi = janet_rng_u32(rng);
|
||||
uint32_t lo = janet_rng_u32(rng);
|
||||
uint64_t big = (uint64_t)(lo) | (((uint64_t) hi) << 32);
|
||||
return ldexp((double)(big >> (64 - 52)), -52);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_rng_make,
|
||||
"(math/rng &opt seed)",
|
||||
"Creates a Psuedo-Random number generator, with an optional seed. "
|
||||
"The seed should be an unsigned 32 bit integer or a buffer. "
|
||||
"Do not use this for cryptography. Returns a core/rng abstract type."
|
||||
) {
|
||||
janet_arity(argc, 0, 1);
|
||||
JanetRNG *rng = janet_abstract(&janet_rng_type, sizeof(JanetRNG));
|
||||
if (argc == 1) {
|
||||
if (janet_checkint(argv[0])) {
|
||||
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
|
||||
janet_rng_seed(rng, seed);
|
||||
} else {
|
||||
JanetByteView bytes = janet_getbytes(argv, 0);
|
||||
janet_rng_longseed(rng, bytes.bytes, bytes.len);
|
||||
}
|
||||
} else {
|
||||
janet_rng_seed(rng, 0);
|
||||
}
|
||||
return janet_wrap_abstract(rng);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_rng_uniform,
|
||||
"(math/rng-uniform rng)",
|
||||
"Extract a random number in the range [0, 1) from the RNG."
|
||||
) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||
return janet_wrap_number(janet_rng_double(rng));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_rng_int,
|
||||
"(math/rng-int rng &opt max)",
|
||||
"Extract a random integer in the range [0, max) for max > 0 from the RNG. "
|
||||
"If max is 0, return 0. If no max is given, the default is 2^31 - 1."
|
||||
) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||
if (argc == 1) {
|
||||
uint32_t word = janet_rng_u32(rng) >> 1;
|
||||
return janet_wrap_integer(word);
|
||||
} else {
|
||||
int32_t max = janet_optnat(argv, argc, 1, INT32_MAX);
|
||||
if (max == 0) return janet_wrap_number(0.0);
|
||||
uint32_t modulo = (uint32_t) max;
|
||||
uint32_t maxgen = INT32_MAX;
|
||||
uint32_t maxword = maxgen - (maxgen % modulo);
|
||||
uint32_t word;
|
||||
do {
|
||||
word = janet_rng_u32(rng) >> 1;
|
||||
} while (word > maxword);
|
||||
return janet_wrap_integer(word % modulo);
|
||||
}
|
||||
}
|
||||
|
||||
static void rng_get_4bytes(JanetRNG *rng, uint8_t *buf) {
|
||||
uint32_t word = janet_rng_u32(rng);
|
||||
buf[0] = word & 0xFF;
|
||||
buf[1] = (word >> 8) & 0xFF;
|
||||
buf[2] = (word >> 16) & 0xFF;
|
||||
buf[3] = (word >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_rng_buffer,
|
||||
"(math/rng-buffer rng n &opt buf)",
|
||||
"Get n random bytes and put them in a buffer. Creates a new buffer if no buffer is "
|
||||
"provided, otherwise appends to the given buffer. Returns the buffer."
|
||||
) {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||
int32_t n = janet_getnat(argv, 1);
|
||||
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, n);
|
||||
|
||||
/* Split into first part (that is divisible by 4), and rest */
|
||||
int32_t first_part = n & ~3;
|
||||
int32_t second_part = n - first_part;
|
||||
|
||||
/* Get first part in chunks of 4 bytes */
|
||||
janet_buffer_extra(buffer, n);
|
||||
uint8_t *buf = buffer->data + buffer->count;
|
||||
for (int32_t i = 0; i < first_part; i += 4) rng_get_4bytes(rng, buf + i);
|
||||
buffer->count += first_part;
|
||||
|
||||
/* Get remaining 0 - 3 bytes */
|
||||
if (second_part) {
|
||||
uint8_t wordbuf[4] = {0};
|
||||
rng_get_4bytes(rng, wordbuf);
|
||||
janet_buffer_push_bytes(buffer, wordbuf, second_part);
|
||||
}
|
||||
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
static const JanetMethod rng_methods[] = {
|
||||
{"uniform", cfun_rng_uniform},
|
||||
{"int", cfun_rng_int},
|
||||
{"buffer", cfun_rng_buffer},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int janet_rng_get(void *p, Janet key, Janet *out) {
|
||||
(void) p;
|
||||
if (!janet_checktype(key, JANET_KEYWORD)) return 0;
|
||||
return janet_getmethod(janet_unwrap_keyword(key), rng_methods, out);
|
||||
}
|
||||
|
||||
static Janet janet_rng_next(void *p, Janet key) {
|
||||
(void) p;
|
||||
return janet_nextmethod(rng_methods, key);
|
||||
}
|
||||
|
||||
/* Get a random number */
|
||||
Janet janet_rand(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(janet_rand,
|
||||
"(math/random)",
|
||||
"Returns a uniformly distributed random number between 0 and 1.") {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
double r = (rand() % RAND_MAX) / ((double) RAND_MAX);
|
||||
return janet_wrap_number(r);
|
||||
return janet_wrap_number(janet_rng_double(&janet_vm.rng));
|
||||
}
|
||||
|
||||
/* Seed the random number generator */
|
||||
Janet janet_srand(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(janet_srand,
|
||||
"(math/seedrandom seed)",
|
||||
"Set the seed for the random number generator. `seed` should be "
|
||||
"an integer or a buffer."
|
||||
) {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t x = janet_getinteger(argv, 0);
|
||||
srand((unsigned) x);
|
||||
if (janet_checkint(argv[0])) {
|
||||
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
|
||||
janet_rng_seed(&janet_vm.rng, seed);
|
||||
} else {
|
||||
JanetByteView bytes = janet_getbytes(argv, 0);
|
||||
janet_rng_longseed(&janet_vm.rng, bytes.bytes, bytes.len);
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
Janet janet_remainder(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
double y = janet_getnumber(argv, 1);
|
||||
return janet_wrap_number(fmod(x, y));
|
||||
}
|
||||
|
||||
#define JANET_DEFINE_MATHOP(name, fop)\
|
||||
Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
#define JANET_DEFINE_NAMED_MATHOP(janet_name, fop, doc)\
|
||||
JANET_CORE_FN(janet_##fop, "(math/" janet_name " x)", doc) {\
|
||||
janet_fixarity(argc, 1); \
|
||||
double x = janet_getnumber(argv, 0); \
|
||||
return janet_wrap_number(fop(x)); \
|
||||
}
|
||||
|
||||
JANET_DEFINE_MATHOP(acos, acos)
|
||||
JANET_DEFINE_MATHOP(asin, asin)
|
||||
JANET_DEFINE_MATHOP(atan, atan)
|
||||
JANET_DEFINE_MATHOP(cos, cos)
|
||||
JANET_DEFINE_MATHOP(cosh, cosh)
|
||||
JANET_DEFINE_MATHOP(sin, sin)
|
||||
JANET_DEFINE_MATHOP(sinh, sinh)
|
||||
JANET_DEFINE_MATHOP(tan, tan)
|
||||
JANET_DEFINE_MATHOP(tanh, tanh)
|
||||
JANET_DEFINE_MATHOP(exp, exp)
|
||||
JANET_DEFINE_MATHOP(log, log)
|
||||
JANET_DEFINE_MATHOP(log10, log10)
|
||||
JANET_DEFINE_MATHOP(sqrt, sqrt)
|
||||
JANET_DEFINE_MATHOP(ceil, ceil)
|
||||
JANET_DEFINE_MATHOP(fabs, fabs)
|
||||
JANET_DEFINE_MATHOP(floor, floor)
|
||||
#define JANET_DEFINE_MATHOP(fop, doc) JANET_DEFINE_NAMED_MATHOP(#fop, fop, doc)
|
||||
|
||||
#define JANET_DEFINE_MATH2OP(name, fop)\
|
||||
Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
JANET_DEFINE_MATHOP(acos, "Returns the arccosine of x.")
|
||||
JANET_DEFINE_MATHOP(asin, "Returns the arcsin of x.")
|
||||
JANET_DEFINE_MATHOP(atan, "Returns the arctangent of x.")
|
||||
JANET_DEFINE_MATHOP(cos, "Returns the cosine of x.")
|
||||
JANET_DEFINE_MATHOP(cosh, "Returns the hyperbolic cosine of x.")
|
||||
JANET_DEFINE_MATHOP(acosh, "Returns the hyperbolic arccosine of x.")
|
||||
JANET_DEFINE_MATHOP(sin, "Returns the sine of x.")
|
||||
JANET_DEFINE_MATHOP(sinh, "Returns the hyperbolic sine of x.")
|
||||
JANET_DEFINE_MATHOP(asinh, "Returns the hyperbolic arcsine of x.")
|
||||
JANET_DEFINE_MATHOP(tan, "Returns the tangent of x.")
|
||||
JANET_DEFINE_MATHOP(tanh, "Returns the hyperbolic tangent of x.")
|
||||
JANET_DEFINE_MATHOP(atanh, "Returns the hyperbolic arctangent of x.")
|
||||
JANET_DEFINE_MATHOP(exp, "Returns e to the power of x.")
|
||||
JANET_DEFINE_MATHOP(exp2, "Returns 2 to the power of x.")
|
||||
JANET_DEFINE_MATHOP(expm1, "Returns e to the power of x minus 1.")
|
||||
JANET_DEFINE_MATHOP(log, "Returns the natural logarithm of x.")
|
||||
JANET_DEFINE_MATHOP(log10, "Returns the log base 10 of x.")
|
||||
JANET_DEFINE_MATHOP(log2, "Returns the log base 2 of x.")
|
||||
JANET_DEFINE_MATHOP(sqrt, "Returns the square root of x.")
|
||||
JANET_DEFINE_MATHOP(cbrt, "Returns the cube root of x.")
|
||||
JANET_DEFINE_MATHOP(ceil, "Returns the smallest integer value number that is not less than x.")
|
||||
JANET_DEFINE_MATHOP(floor, "Returns the largest integer value number that is not greater than x.")
|
||||
JANET_DEFINE_MATHOP(trunc, "Returns the integer between x and 0 nearest to x.")
|
||||
JANET_DEFINE_MATHOP(round, "Returns the integer nearest to x.")
|
||||
JANET_DEFINE_MATHOP(log1p, "Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)")
|
||||
JANET_DEFINE_MATHOP(erf, "Returns the error function of x.")
|
||||
JANET_DEFINE_MATHOP(erfc, "Returns the complementary error function of x.")
|
||||
JANET_DEFINE_NAMED_MATHOP("log-gamma", lgamma, "Returns log-gamma(x).")
|
||||
JANET_DEFINE_NAMED_MATHOP("abs", fabs, "Return the absolute value of x.")
|
||||
JANET_DEFINE_NAMED_MATHOP("gamma", tgamma, "Returns gamma(x).")
|
||||
|
||||
#define JANET_DEFINE_MATH2OP(name, fop, signature, doc)\
|
||||
JANET_CORE_FN(janet_##name, signature, doc) {\
|
||||
janet_fixarity(argc, 2); \
|
||||
double lhs = janet_getnumber(argv, 0); \
|
||||
double rhs = janet_getnumber(argv, 1); \
|
||||
return janet_wrap_number(fop(lhs, rhs)); \
|
||||
}\
|
||||
}
|
||||
|
||||
JANET_DEFINE_MATH2OP(atan2, atan2)
|
||||
JANET_DEFINE_MATH2OP(pow, pow)
|
||||
JANET_DEFINE_MATH2OP(atan2, atan2, "(math/atan2 y x)", "Returns the arctangent of y/x. Works even when x is 0.")
|
||||
JANET_DEFINE_MATH2OP(pow, pow, "(math/pow a x)", "Returns a to the power of x.")
|
||||
JANET_DEFINE_MATH2OP(hypot, hypot, "(math/hypot a b)", "Returns c from the equation c^2 = a^2 + b^2.")
|
||||
JANET_DEFINE_MATH2OP(nextafter, nextafter, "(math/next x y)", "Returns the next representable floating point value after x in the direction of y.")
|
||||
|
||||
static Janet janet_not(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(janet_not, "(not x)", "Returns the boolean inverse of x.") {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_boolean(!janet_truthy(argv[0]));
|
||||
}
|
||||
|
||||
static const JanetReg math_cfuns[] = {
|
||||
{
|
||||
"%", janet_remainder,
|
||||
JDOC("(% dividend divisor)\n\n"
|
||||
"Returns the remainder of dividend / divisor.")
|
||||
},
|
||||
{
|
||||
"not", janet_not,
|
||||
JDOC("(not x)\n\nReturns the boolean inverse of x.")
|
||||
},
|
||||
{
|
||||
"math/random", janet_rand,
|
||||
JDOC("(math/random)\n\n"
|
||||
"Returns a uniformly distributed random number between 0 and 1.")
|
||||
},
|
||||
{
|
||||
"math/seedrandom", janet_srand,
|
||||
JDOC("(math/seedrandom seed)\n\n"
|
||||
"Set the seed for the random number generator. 'seed' should be an "
|
||||
"an integer.")
|
||||
},
|
||||
{
|
||||
"math/cos", janet_cos,
|
||||
JDOC("(math/cos x)\n\n"
|
||||
"Returns the cosine of x.")
|
||||
},
|
||||
{
|
||||
"math/sin", janet_sin,
|
||||
JDOC("(math/sin x)\n\n"
|
||||
"Returns the sine of x.")
|
||||
},
|
||||
{
|
||||
"math/tan", janet_tan,
|
||||
JDOC("(math/tan x)\n\n"
|
||||
"Returns the tangent of x.")
|
||||
},
|
||||
{
|
||||
"math/acos", janet_acos,
|
||||
JDOC("(math/acos x)\n\n"
|
||||
"Returns the arccosine of x.")
|
||||
},
|
||||
{
|
||||
"math/asin", janet_asin,
|
||||
JDOC("(math/asin x)\n\n"
|
||||
"Returns the arcsine of x.")
|
||||
},
|
||||
{
|
||||
"math/atan", janet_atan,
|
||||
JDOC("(math/atan x)\n\n"
|
||||
"Returns the arctangent of x.")
|
||||
},
|
||||
{
|
||||
"math/exp", janet_exp,
|
||||
JDOC("(math/exp x)\n\n"
|
||||
"Returns e to the power of x.")
|
||||
},
|
||||
{
|
||||
"math/log", janet_log,
|
||||
JDOC("(math/log x)\n\n"
|
||||
"Returns log base 2 of x.")
|
||||
},
|
||||
{
|
||||
"math/log10", janet_log10,
|
||||
JDOC("(math/log10 x)\n\n"
|
||||
"Returns log base 10 of x.")
|
||||
},
|
||||
{
|
||||
"math/sqrt", janet_sqrt,
|
||||
JDOC("(math/sqrt x)\n\n"
|
||||
"Returns the square root of x.")
|
||||
},
|
||||
{
|
||||
"math/floor", janet_floor,
|
||||
JDOC("(math/floor x)\n\n"
|
||||
"Returns the largest integer value number that is not greater than x.")
|
||||
},
|
||||
{
|
||||
"math/ceil", janet_ceil,
|
||||
JDOC("(math/ceil x)\n\n"
|
||||
"Returns the smallest integer value number that is not less than x.")
|
||||
},
|
||||
{
|
||||
"math/pow", janet_pow,
|
||||
JDOC("(math/pow a x)\n\n"
|
||||
"Return a to the power of x.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
static double janet_gcd(double x, double y) {
|
||||
if (isnan(x) || isnan(y)) {
|
||||
#ifdef NAN
|
||||
return NAN;
|
||||
#else
|
||||
return 0.0 / 0.0;
|
||||
#endif
|
||||
}
|
||||
if (isinf(x) || isinf(y)) return INFINITY;
|
||||
while (y != 0) {
|
||||
double temp = y;
|
||||
y = fmod(x, y);
|
||||
x = temp;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static double janet_lcm(double x, double y) {
|
||||
return (x / janet_gcd(x, y)) * y;
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_gcd, "(math/gcd x y)",
|
||||
"Returns the greatest common divisor between x and y.") {
|
||||
janet_fixarity(argc, 2);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
double y = janet_getnumber(argv, 1);
|
||||
return janet_wrap_number(janet_gcd(x, y));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_lcm, "(math/lcm x y)",
|
||||
"Returns the least common multiple of x and y.") {
|
||||
janet_fixarity(argc, 2);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
double y = janet_getnumber(argv, 1);
|
||||
return janet_wrap_number(janet_lcm(x, y));
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_math(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, math_cfuns);
|
||||
JanetRegExt math_cfuns[] = {
|
||||
JANET_CORE_REG("not", janet_not),
|
||||
JANET_CORE_REG("math/random", janet_rand),
|
||||
JANET_CORE_REG("math/seedrandom", janet_srand),
|
||||
JANET_CORE_REG("math/cos", janet_cos),
|
||||
JANET_CORE_REG("math/sin", janet_sin),
|
||||
JANET_CORE_REG("math/tan", janet_tan),
|
||||
JANET_CORE_REG("math/acos", janet_acos),
|
||||
JANET_CORE_REG("math/asin", janet_asin),
|
||||
JANET_CORE_REG("math/atan", janet_atan),
|
||||
JANET_CORE_REG("math/exp", janet_exp),
|
||||
JANET_CORE_REG("math/log", janet_log),
|
||||
JANET_CORE_REG("math/log10", janet_log10),
|
||||
JANET_CORE_REG("math/log2", janet_log2),
|
||||
JANET_CORE_REG("math/sqrt", janet_sqrt),
|
||||
JANET_CORE_REG("math/cbrt", janet_cbrt),
|
||||
JANET_CORE_REG("math/floor", janet_floor),
|
||||
JANET_CORE_REG("math/ceil", janet_ceil),
|
||||
JANET_CORE_REG("math/pow", janet_pow),
|
||||
JANET_CORE_REG("math/abs", janet_fabs),
|
||||
JANET_CORE_REG("math/sinh", janet_sinh),
|
||||
JANET_CORE_REG("math/cosh", janet_cosh),
|
||||
JANET_CORE_REG("math/tanh", janet_tanh),
|
||||
JANET_CORE_REG("math/atanh", janet_atanh),
|
||||
JANET_CORE_REG("math/asinh", janet_asinh),
|
||||
JANET_CORE_REG("math/acosh", janet_acosh),
|
||||
JANET_CORE_REG("math/atan2", janet_atan2),
|
||||
JANET_CORE_REG("math/rng", cfun_rng_make),
|
||||
JANET_CORE_REG("math/rng-uniform", cfun_rng_uniform),
|
||||
JANET_CORE_REG("math/rng-int", cfun_rng_int),
|
||||
JANET_CORE_REG("math/rng-buffer", cfun_rng_buffer),
|
||||
JANET_CORE_REG("math/hypot", janet_hypot),
|
||||
JANET_CORE_REG("math/exp2", janet_exp2),
|
||||
JANET_CORE_REG("math/log1p", janet_log1p),
|
||||
JANET_CORE_REG("math/gamma", janet_tgamma),
|
||||
JANET_CORE_REG("math/log-gamma", janet_lgamma),
|
||||
JANET_CORE_REG("math/erfc", janet_erfc),
|
||||
JANET_CORE_REG("math/erf", janet_erf),
|
||||
JANET_CORE_REG("math/expm1", janet_expm1),
|
||||
JANET_CORE_REG("math/trunc", janet_trunc),
|
||||
JANET_CORE_REG("math/round", janet_round),
|
||||
JANET_CORE_REG("math/next", janet_nextafter),
|
||||
JANET_CORE_REG("math/gcd", janet_cfun_gcd),
|
||||
JANET_CORE_REG("math/lcm", janet_cfun_lcm),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, math_cfuns);
|
||||
janet_register_abstract_type(&janet_rng_type);
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
janet_def(env, "math/pi", janet_wrap_number(3.1415926535897931),
|
||||
JDOC("The value pi."));
|
||||
janet_def(env, "math/e", janet_wrap_number(2.7182818284590451),
|
||||
JDOC("The base of the natural log."));
|
||||
janet_def(env, "math/inf", janet_wrap_number(INFINITY),
|
||||
JDOC("The number representing positive infinity"));
|
||||
JANET_CORE_DEF(env, "math/pi", janet_wrap_number(3.1415926535897931),
|
||||
"The value pi.");
|
||||
JANET_CORE_DEF(env, "math/e", janet_wrap_number(2.7182818284590451),
|
||||
"The base of the natural log.");
|
||||
JANET_CORE_DEF(env, "math/inf", janet_wrap_number(INFINITY),
|
||||
"The number representing positive infinity");
|
||||
JANET_CORE_DEF(env, "math/-inf", janet_wrap_number(-INFINITY),
|
||||
"The number representing negative infinity");
|
||||
JANET_CORE_DEF(env, "math/int32-min", janet_wrap_number(INT32_MIN),
|
||||
"The minimum contiguous integer representable by a 32 bit signed integer");
|
||||
JANET_CORE_DEF(env, "math/int32-max", janet_wrap_number(INT32_MAX),
|
||||
"The maximum contiguous integer represtenable by a 32 bit signed integer");
|
||||
JANET_CORE_DEF(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE),
|
||||
"The minimum contiguous integer representable by a double (2^53)");
|
||||
JANET_CORE_DEF(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE),
|
||||
"The maximum contiguous integer represtenable by a double (-(2^53))");
|
||||
#ifdef NAN
|
||||
JANET_CORE_DEF(env, "math/nan", janet_wrap_number(NAN), "Not a number (IEEE-754 NaN)");
|
||||
#else
|
||||
JANET_CORE_DEF(env, "math/nan", janet_wrap_number(0.0 / 0.0), "Not a number (IEEE-754 NaN)");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
1034
src/core/net.c
Normal file
1034
src/core/net.c
Normal file
File diff suppressed because it is too large
Load Diff
2668
src/core/os.c
2668
src/core/os.c
File diff suppressed because it is too large
Load Diff
926
src/core/parse.c
926
src/core/parse.c
File diff suppressed because it is too large
Load Diff
1688
src/core/peg.c
1688
src/core/peg.c
File diff suppressed because it is too large
Load Diff
1038
src/core/pp.c
1038
src/core/pp.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user