mirror of
https://github.com/janet-lang/janet
synced 2026-04-06 23:11:25 +00:00
Compare commits
2142 Commits
0.1.0
...
circleci-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3fa24c1e6 | ||
|
|
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 | ||
|
|
b61d1a0a0e | ||
|
|
89ef4eb634 | ||
|
|
114a45306d | ||
|
|
fe27df528c | ||
|
|
8ab60e475a | ||
|
|
6321c30cb1 | ||
|
|
8343c9edd1 | ||
|
|
74e1a3273f | ||
|
|
1394dbbd57 | ||
|
|
f6a3853131 | ||
|
|
49465f71f3 | ||
|
|
960cf76eb5 | ||
|
|
1b735564fa | ||
|
|
7ae01d25dd | ||
|
|
cb5263d2d8 | ||
|
|
602092f6d5 | ||
|
|
d3a067a665 | ||
|
|
98a26f5ce3 | ||
|
|
09d9dca5f5 | ||
|
|
8a3f512746 | ||
|
|
19e59705b9 | ||
|
|
367c9da856 | ||
|
|
4bcf6565cd | ||
|
|
0c950d0846 | ||
|
|
7ba925c50a | ||
|
|
cb3b9dd76f | ||
|
|
f4fa55027b | ||
|
|
0fe11adb9c | ||
|
|
b138ee6e8e | ||
|
|
a66f19f636 | ||
|
|
c76f4e89d8 | ||
|
|
85a211b26b | ||
|
|
fe3620529f | ||
|
|
a7551e9b4e | ||
|
|
46c540b93e | ||
|
|
32c209ede9 | ||
|
|
0d293cd3f5 | ||
|
|
f284776490 | ||
|
|
38a7e4faf1 | ||
|
|
c333cbfa55 | ||
|
|
f72aa64f41 | ||
|
|
d85892edc8 | ||
|
|
56383b2ecc | ||
|
|
0d729eaab1 | ||
|
|
17ab654ccb | ||
|
|
872d03ae1d | ||
|
|
ee5fa54134 | ||
|
|
68e00cdb7a | ||
|
|
5bf9e4fc89 | ||
|
|
7350bf5dd9 | ||
|
|
e755f98300 | ||
|
|
8ee2f0a1d6 | ||
|
|
0726de34ff | ||
|
|
00301ad26b | ||
|
|
611543c48b | ||
|
|
4d81fbc238 | ||
|
|
c5012ca4c1 | ||
|
|
e68a889fa9 | ||
|
|
795e7a9de8 | ||
|
|
090a6a8c5c | ||
|
|
2bbf9fdcc5 | ||
|
|
0025f6ac87 | ||
|
|
737b2449f0 | ||
|
|
f7a0133eb1 | ||
|
|
48b179d67e | ||
|
|
d1a075b2a6 | ||
|
|
2bad24371d | ||
|
|
bf8d5da3dc | ||
|
|
4a6fcb5e23 | ||
|
|
5ba969f91d | ||
|
|
26818a5e5c | ||
|
|
b84b0e4828 | ||
|
|
b4934ceddc | ||
|
|
c4114fbcdb | ||
|
|
95f2bbe0a0 | ||
|
|
63137b8107 | ||
|
|
2c1b506213 | ||
|
|
612a245961 | ||
|
|
4b8edef58c | ||
|
|
82cddef5bb | ||
|
|
d0fc29338c | ||
|
|
4eeadd7463 | ||
|
|
f0fcdf6bc5 | ||
|
|
2a333f8359 | ||
|
|
0dd867d508 | ||
|
|
e3f902cb8a | ||
|
|
c651b6f67c | ||
|
|
3a9b50ea4a | ||
|
|
1304f9263b | ||
|
|
90313afd40 | ||
|
|
99f176f37b | ||
|
|
d0ec89c7c1 | ||
|
|
170e785b72 | ||
|
|
e53778d5d8 | ||
|
|
192705113e | ||
|
|
97a42ea17b | ||
|
|
2cd489b9d4 | ||
|
|
ff0d3a0081 | ||
|
|
282c02c475 | ||
|
|
798c88b4c8 | ||
|
|
83f4a11bf3 | ||
|
|
d7626f8c57 | ||
|
|
1efca2ebe7 | ||
|
|
40845b5c1b | ||
|
|
84fb07dd5a | ||
|
|
62cb3f81fe | ||
|
|
16ebb11181 | ||
|
|
115ed9cbb9 | ||
|
|
3ae6f64de5 | ||
|
|
ff3f7487a4 | ||
|
|
f0afb3c311 | ||
|
|
5b1a3b8208 | ||
|
|
b1e0849a2f | ||
|
|
67f26b7d72 | ||
|
|
d5bab72620 | ||
|
|
aa079e3145 | ||
|
|
d64a57297d | ||
|
|
be85196de8 | ||
|
|
eae4e0dede | ||
|
|
92e9e64945 | ||
|
|
63dd6d03f4 | ||
|
|
2a79d2e749 | ||
|
|
6f3bc3d577 | ||
|
|
ef5eed2c21 | ||
|
|
5865692401 | ||
|
|
b626e73d19 | ||
|
|
b535c91ee1 | ||
|
|
7b28032f5c | ||
|
|
0fdd404a71 | ||
|
|
1f98eff33a | ||
|
|
338b31f5a2 | ||
|
|
b60e3e302a | ||
|
|
5b62c8e6db | ||
|
|
cd6a7793e8 | ||
|
|
5afb00859a | ||
|
|
001917f8d9 | ||
|
|
b9c0fc8201 | ||
|
|
d8b0a5ed01 | ||
|
|
5fa96a6f8c | ||
|
|
dd3fc24a1e | ||
|
|
ddba0010b0 | ||
|
|
337a498edb | ||
|
|
5fff36d047 | ||
|
|
a679f60e07 | ||
|
|
58d480539c | ||
|
|
6afaacf2af | ||
|
|
e9c94598e6 | ||
|
|
29ec30c79f | ||
|
|
122312dbf6 | ||
|
|
618f8d6818 | ||
|
|
0d4ab7dee0 | ||
|
|
6b4824c2ab | ||
|
|
8dde89126e | ||
|
|
56927e1b81 | ||
|
|
9e6254bf56 | ||
|
|
fe22a8db39 | ||
|
|
d724c5b959 | ||
|
|
ca9c017ec4 | ||
|
|
65be318306 | ||
|
|
7c4671d98f | ||
|
|
7880d73201 | ||
|
|
00f0f628e8 | ||
|
|
21b7583a7c | ||
|
|
42c6aca526 | ||
|
|
52b8781684 | ||
|
|
5d39570ec9 | ||
|
|
28331ad6ab | ||
|
|
129ec1e3c5 | ||
|
|
bdcd3a3dbf | ||
|
|
6c8f49206d | ||
|
|
b06f7226c4 | ||
|
|
2bcedd5920 | ||
|
|
5c84f0f5d9 | ||
|
|
424073bbb8 | ||
|
|
e9a80d4e4a | ||
|
|
1ec7f04642 | ||
|
|
59f6c335ad | ||
|
|
6b95326d7c | ||
|
|
5a3190d471 | ||
|
|
e7a8958c63 | ||
|
|
017ee2b0d1 | ||
|
|
a7933f5f08 | ||
|
|
be7fc79b6f | ||
|
|
6c8da9fe5c | ||
|
|
17283241ab | ||
|
|
2c94aa1a6a | ||
|
|
e5d2752329 | ||
|
|
70b4c8ae84 | ||
|
|
876a68f620 | ||
|
|
6c91e5fae0 | ||
|
|
55c091e898 | ||
|
|
3f5ba64f30 | ||
|
|
3bd7787efa | ||
|
|
39198de60a | ||
|
|
9723ddb96b | ||
|
|
02673dd791 | ||
|
|
ac9935c95f | ||
|
|
cc5b4eac0a | ||
|
|
77ea11c603 | ||
|
|
003472354d | ||
|
|
131ee29190 | ||
|
|
05a957c524 | ||
|
|
99e14a9b70 | ||
|
|
03dbd79165 | ||
|
|
f7a25ecae3 | ||
|
|
22e49bc0fc | ||
|
|
696866ae51 | ||
|
|
8333c22e8a | ||
|
|
e286e82144 | ||
|
|
8a5ede21f7 | ||
|
|
a412eecd36 | ||
|
|
24b9ae7820 | ||
|
|
7484a396ac | ||
|
|
79184ab05d | ||
|
|
fb6dd2c83f | ||
|
|
b2146a4c1d | ||
|
|
df13a8b967 | ||
|
|
dfb771700a | ||
|
|
56e5c19aa9 | ||
|
|
e8c0dcd14e | ||
|
|
f444bdd052 | ||
|
|
090068c784 | ||
|
|
85a190b971 | ||
|
|
3437880c78 | ||
|
|
4b01409d2d | ||
|
|
f0e125b304 | ||
|
|
e4503df8b6 | ||
|
|
db0313b379 | ||
|
|
cd16888beb | ||
|
|
49dd75b0e5 | ||
|
|
2abd97d095 | ||
|
|
34a69d0318 | ||
|
|
a77ce76928 | ||
|
|
c971d8ab6e | ||
|
|
0a15539d7b | ||
|
|
21d4b8fe1f | ||
|
|
6f64b0c152 |
@@ -1,11 +0,0 @@
|
||||
image: freebsd
|
||||
packages:
|
||||
- gmake
|
||||
- gcc
|
||||
sources:
|
||||
- https://github.com/bakpakin/janet.git
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake CC=gcc
|
||||
gmake test CC=gcc
|
||||
12
.builds/freebsd.yml
Normal file
12
.builds/freebsd.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
image: freebsd/12.x
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
sudo gmake install
|
||||
gmake test-install
|
||||
23
.builds/linux.yml
Normal file
23
.builds/linux.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
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
|
||||
sudo jpm --verbose install circlet
|
||||
sudo jpm --verbose install spork
|
||||
33
.builds/openbsd.yml
Normal file
33
.builds/openbsd.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
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 -Dtyped_array=false -Dreduced_os=true
|
||||
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
|
||||
doas jpm --verbose install circlet
|
||||
|
||||
14
.circleci/config.yml
Normal file
14
.circleci/config.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
# for later
|
||||
windows: circleci/windows@2.2.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
macos:
|
||||
xcode: 11.3.0
|
||||
steps:
|
||||
- checkout
|
||||
- run: make
|
||||
- run: make test
|
||||
10
.gitattributes
vendored
Normal file
10
.gitattributes
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
*.janet linguist-language=Clojure
|
||||
|
||||
*.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
|
||||
34
.gitignore
vendored
34
.gitignore
vendored
@@ -4,12 +4,36 @@ dst
|
||||
janet
|
||||
!*/**/janet
|
||||
/build
|
||||
/builddir
|
||||
/Build
|
||||
/Release
|
||||
/Debug
|
||||
/Emscripten
|
||||
/src/include/generated/*.h
|
||||
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 file I use.
|
||||
temp.janet
|
||||
|
||||
# Emscripten
|
||||
*.bc
|
||||
@@ -22,6 +46,7 @@ janet.wasm
|
||||
|
||||
# Generate test files
|
||||
*.out
|
||||
.orig
|
||||
|
||||
# Tools
|
||||
xxd
|
||||
@@ -29,6 +54,7 @@ xxd.exe
|
||||
|
||||
# VSCode
|
||||
.vs
|
||||
.clangd
|
||||
|
||||
# Swap files
|
||||
*.swp
|
||||
@@ -38,6 +64,11 @@ tags
|
||||
|
||||
# Valgrind files
|
||||
vgcore.*
|
||||
*.out.*
|
||||
|
||||
# Wix artifacts
|
||||
*.msi
|
||||
*.wixpdb
|
||||
|
||||
# Created by https://www.gitignore.io/api/c
|
||||
|
||||
@@ -109,3 +140,6 @@ compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
|
||||
# End of https://www.gitignore.io/api/cmake
|
||||
|
||||
# Astyle
|
||||
*.orig
|
||||
|
||||
@@ -2,7 +2,9 @@ language: c
|
||||
script:
|
||||
- make
|
||||
- make test
|
||||
- make janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
- sudo make install
|
||||
- make test-install
|
||||
- make build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
@@ -14,10 +16,10 @@ 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: janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
file: build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
|
||||
draft: true
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
repo: bakpakin/janet
|
||||
repo: janet-lang/janet
|
||||
condition: "$CC = clang"
|
||||
|
||||
553
CHANGELOG.md
Normal file
553
CHANGELOG.md
Normal file
@@ -0,0 +1,553 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 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
|
||||
like objects with methods.
|
||||
- Add parser/insert to modify parser state programmatically
|
||||
- Add debug/stacktrace for easy, pretty stacktraces
|
||||
- Remove the status-pp function
|
||||
- Update API to run-context to be much more sane
|
||||
- Add :lflags option to cook/make-native
|
||||
- Disallow NaNs as table or struct keys
|
||||
- Update module resolution paths and format
|
||||
|
||||
## 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.
|
||||
- Added this changelog.
|
||||
- Added peg module (Parsing Expression Grammars)
|
||||
- Move hand written documentation into website repository.
|
||||
@@ -29,9 +29,42 @@ 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
|
||||
|
||||
For changes to the VM and Core code, you will probably need to know C. Janet is programmed with
|
||||
a subset of C99 that works with Microsoft Visual C++. This means most of C99 but with the following
|
||||
omissions.
|
||||
|
||||
* 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.
|
||||
The code must also build with emscripten, even if some features are not available, although
|
||||
this is not a priority.
|
||||
|
||||
Code should compile warning free and run valgrind clean. I find that these two criteria are some
|
||||
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.
|
||||
|
||||
## Suggesting Changes
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018 Calvin Rose
|
||||
Copyright (c) 2020 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
|
||||
|
||||
403
Makefile
403
Makefile
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018 Calvin Rose
|
||||
# Copyright (c) 2021 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,174 +24,327 @@
|
||||
|
||||
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
|
||||
JANET_TARGET=janet
|
||||
JANET_LIBRARY=libjanet.so
|
||||
JANET_PATH?=/usr/local/lib/janet
|
||||
INCLUDEDIR?=$(PREFIX)/include
|
||||
BINDIR?=$(PREFIX)/bin
|
||||
LIBDIR?=$(PREFIX)/lib
|
||||
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 2> /dev/null || echo local)\""
|
||||
CLIBS=-lm -lpthread
|
||||
JANET_TARGET=build/janet
|
||||
JANET_LIBRARY=build/libjanet.so
|
||||
JANET_STATIC_LIBRARY=build/libjanet.a
|
||||
JANET_PATH?=$(LIBDIR)/janet
|
||||
JANET_MANPATH?=$(PREFIX)/share/man/man1/
|
||||
JANET_PKG_CONFIG_PATH?=$(LIBDIR)/pkgconfig
|
||||
DEBUGGER=gdb
|
||||
SONAME_SETTER=-Wl,-soname,
|
||||
|
||||
# For cross compilation
|
||||
HOSTCC?=$(CC)
|
||||
HOSTAR?=$(AR)
|
||||
CFLAGS?=-O2
|
||||
LDFLAGS?=-rdynamic
|
||||
|
||||
COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC
|
||||
BOOT_CFLAGS:=-DJANET_BOOTSTRAP -DJANET_BUILD=$(JANET_BUILD) -O0 -g $(COMMON_CFLAGS)
|
||||
BUILD_CFLAGS:=$(CFLAGS) $(COMMON_CFLAGS)
|
||||
|
||||
# For installation
|
||||
LDCONFIG:=ldconfig "$(LIBDIR)"
|
||||
|
||||
# Check OS
|
||||
UNAME:=$(shell uname -s)
|
||||
LDCONFIG:=ldconfig
|
||||
ifeq ($(UNAME), Darwin)
|
||||
# Add other macos/clang flags
|
||||
LDCONFIG:=
|
||||
else
|
||||
CFLAGS:=$(CFLAGS) -rdynamic
|
||||
CLIBS:=$(CLIBS) -lrt
|
||||
CLIBS:=$(CLIBS) -ldl
|
||||
SONAME_SETTER:=-Wl,-install_name,
|
||||
LDCONFIG:=true
|
||||
else ifeq ($(UNAME), Linux)
|
||||
CLIBS:=$(CLIBS) -lrt -ldl
|
||||
endif
|
||||
# For other unix likes, add flags here!
|
||||
ifeq ($(UNAME), Haiku)
|
||||
LDCONFIG:=true
|
||||
LDFLAGS=-Wl,--export-dynamic
|
||||
endif
|
||||
|
||||
# Source headers
|
||||
JANET_HEADERS=$(sort $(wildcard src/include/janet/*.h))
|
||||
JANET_LOCAL_HEADERS=$(sort $(wildcard src/*/*.h))
|
||||
|
||||
# Source files
|
||||
JANET_CORE_SOURCES=$(sort $(wildcard src/core/*.c)) src/core/core.gen.c
|
||||
JANET_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c)) src/mainclient/init.gen.c
|
||||
JANET_WEBCLIENT_SOURCES=$(sort $(wildcard src/webclient/*.c)) src/webclient/webinit.gen.c
|
||||
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY)
|
||||
|
||||
##########################################################
|
||||
##### The main interpreter program and shared object #####
|
||||
##########################################################
|
||||
|
||||
JANET_ALL_SOURCES=$(JANET_CORE_SOURCES) \
|
||||
$(JANET_MAINCLIENT_SOURCES)
|
||||
|
||||
JANET_CORE_OBJECTS=$(patsubst %.c,%.o,$(JANET_CORE_SOURCES))
|
||||
JANET_ALL_OBJECTS=$(patsubst %.c,%.o,$(JANET_ALL_SOURCES))
|
||||
|
||||
%.o: %.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
$(JANET_TARGET): $(JANET_ALL_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_LIBRARY): $(JANET_CORE_OBJECTS)
|
||||
$(CC) $(CFLAGS) -shared -o $@ $^ $(CLIBS)
|
||||
$(shell mkdir -p build/core build/c build/boot)
|
||||
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.h
|
||||
|
||||
######################
|
||||
##### Emscripten #####
|
||||
##### Name Files #####
|
||||
######################
|
||||
|
||||
EMCC=emcc
|
||||
EMCCFLAGS=-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=janet.js
|
||||
JANET_WEB_SOURCES=$(JANET_CORE_SOURCES) $(JANET_WEBCLIENT_SOURCES)
|
||||
JANET_EMOBJECTS=$(patsubst %.c,%.bc,$(JANET_WEB_SOURCES))
|
||||
JANET_HEADERS=src/include/janet.h src/conf/janetconf.h
|
||||
|
||||
%.bc: %.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
|
||||
$(EMCC) $(EMCCFLAGS) -o $@ -c $<
|
||||
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_EMTARGET): $(JANET_EMOBJECTS)
|
||||
$(EMCC) $(EMCCFLAGS) -shared -o $@ $^
|
||||
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/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/string.c \
|
||||
src/core/strtod.c \
|
||||
src/core/struct.c \
|
||||
src/core/symcache.c \
|
||||
src/core/table.c \
|
||||
src/core/thread.c \
|
||||
src/core/tuple.c \
|
||||
src/core/typedarray.c \
|
||||
src/core/util.c \
|
||||
src/core/value.c \
|
||||
src/core/vector.c \
|
||||
src/core/vm.c \
|
||||
src/core/wrap.c
|
||||
|
||||
#############################
|
||||
##### Generated C files #####
|
||||
#############################
|
||||
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
|
||||
|
||||
xxd: src/tools/xxd.c
|
||||
$(CC) $< -o $@
|
||||
##########################################################
|
||||
##### The bootstrap interpreter that creates janet.c #####
|
||||
##########################################################
|
||||
|
||||
%.gen.c: %.janet xxd
|
||||
./xxd $< $@ janet_gen_$(*F)
|
||||
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 $<
|
||||
|
||||
build/janet_boot: $(JANET_BOOT_OBJECTS)
|
||||
$(CC) $(BOOT_CFLAGS) -o $@ $(JANET_BOOT_OBJECTS) $(CLIBS)
|
||||
|
||||
# Now the reason we bootstrap in the first place
|
||||
build/c/janet.c: build/janet_boot src/boot/boot.janet
|
||||
build/janet_boot . JANET_PATH '$(JANET_PATH)' > $@
|
||||
cksum $@
|
||||
|
||||
########################
|
||||
##### Amalgamation #####
|
||||
########################
|
||||
|
||||
SONAME=libjanet.so.1.15
|
||||
|
||||
build/c/shell.c: src/mainclient/shell.c
|
||||
cp $< $@
|
||||
|
||||
build/janet.h: $(JANET_TARGET) src/include/janet.h src/conf/janetconf.h
|
||||
./$(JANET_TARGET) tools/patch-header.janet src/include/janet.h src/conf/janetconf.h $@
|
||||
|
||||
build/janetconf.h: src/conf/janetconf.h
|
||||
cp $< $@
|
||||
|
||||
build/janet.o: build/c/janet.c src/conf/janetconf.h src/include/janet.h
|
||||
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@
|
||||
|
||||
build/shell.o: build/c/shell.c src/conf/janetconf.h src/include/janet.h
|
||||
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@
|
||||
|
||||
$(JANET_TARGET): build/janet.o build/shell.o
|
||||
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_LIBRARY): build/janet.o build/shell.o
|
||||
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
|
||||
|
||||
$(JANET_STATIC_LIBRARY): build/janet.o build/shell.o
|
||||
$(HOSTAR) rcs $@ $^
|
||||
|
||||
###################
|
||||
##### Testing #####
|
||||
###################
|
||||
|
||||
TEST_SOURCES=$(wildcard ctest/*.c)
|
||||
TEST_OBJECTS=$(patsubst %.c,%.o,$(TEST_SOURCES))
|
||||
TEST_PROGRAMS=$(patsubst %.c,%.out,$(TEST_SOURCES))
|
||||
# Testing assumes HOSTCC=CC
|
||||
|
||||
TEST_SCRIPTS=$(wildcard test/suite*.janet)
|
||||
|
||||
ctest/%.o: ctest/%.c $(JANET_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
ctest/%.out: ctest/%.o $(JANET_CORE_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(CLIBS)
|
||||
|
||||
repl: $(JANET_TARGET)
|
||||
./$(JANET_TARGET)
|
||||
|
||||
debug: $(JANET_TARGET)
|
||||
$(DEBUGGER) ./$(JANET_TARGET)
|
||||
|
||||
VALGRIND_COMMAND=valgrind --leak-check=full
|
||||
|
||||
valgrind: $(JANET_TARGET)
|
||||
valgrind --leak-check=full -v ./$(JANET_TARGET)
|
||||
$(VALGRIND_COMMAND) ./$(JANET_TARGET)
|
||||
|
||||
test: $(JANET_TARGET) $(TEST_PROGRAMS)
|
||||
for f in ctest/*.out; do "$$f" || exit; done
|
||||
for f in test/*.janet; do ./$(JANET_TARGET) "$$f" || exit; done
|
||||
|
||||
VALGRIND_COMMAND=valgrind --leak-check=full -v
|
||||
for f in test/suite*.janet; do ./$(JANET_TARGET) "$$f" || exit; done
|
||||
for f in examples/*.janet; do ./$(JANET_TARGET) -k "$$f"; done
|
||||
./$(JANET_TARGET) -k jpm
|
||||
|
||||
valtest: $(JANET_TARGET) $(TEST_PROGRAMS)
|
||||
for f in ctest/*.out; do $(VALGRIND_COMMAND) "$$f" || exit; done
|
||||
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
|
||||
$(VALGRIND_COMMAND) ./$(JANET_TARGET) -k jpm
|
||||
|
||||
###################
|
||||
##### Natives #####
|
||||
###################
|
||||
callgrind: $(JANET_TARGET)
|
||||
for f in test/suite*.janet; do valgrind --tool=callgrind ./$(JANET_TARGET) "$$f" || exit; done
|
||||
|
||||
natives: $(JANET_TARGET)
|
||||
$(MAKE) -C natives/json
|
||||
$(MAKE) -j 8 -C natives/sqlite3
|
||||
########################
|
||||
##### Distribution #####
|
||||
########################
|
||||
|
||||
clean-natives:
|
||||
$(MAKE) -C natives/json clean
|
||||
$(MAKE) -C natives/sqlite3 clean
|
||||
dist: build/janet-dist.tar.gz
|
||||
|
||||
build/janet-%.tar.gz: $(JANET_TARGET) \
|
||||
build/janet.h \
|
||||
jpm.1 janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
|
||||
build/doc.html README.md build/c/janet.c build/c/shell.c jpm
|
||||
$(eval JANET_DIST_DIR = "janet-$(shell basename $*)")
|
||||
mkdir -p build/$(JANET_DIST_DIR)
|
||||
cp -r $^ build/$(JANET_DIST_DIR)/
|
||||
cd build && tar -czvf ../$@ $(JANET_DIST_DIR)
|
||||
|
||||
#########################
|
||||
##### Documentation #####
|
||||
#########################
|
||||
|
||||
docs: build/doc.html
|
||||
|
||||
build/doc.html: $(JANET_TARGET) tools/gendoc.janet
|
||||
$(JANET_TARGET) tools/gendoc.janet > build/doc.html
|
||||
|
||||
########################
|
||||
##### Installation #####
|
||||
########################
|
||||
|
||||
build/jpm: jpm $(JANET_TARGET)
|
||||
$(JANET_TARGET) tools/patch-jpm.janet jpm build/jpm "--libpath=$(LIBDIR)" "--headerpath=$(INCLUDEDIR)/janet" "--binpath=$(BINDIR)"
|
||||
chmod +x build/jpm
|
||||
|
||||
.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." >> $@
|
||||
$(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/jpm build/janet.h
|
||||
mkdir -p '$(DESTDIR)$(BINDIR)'
|
||||
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
||||
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
||||
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')'
|
||||
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
|
||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so'
|
||||
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME)
|
||||
cp -rf build/jpm '$(DESTDIR)$(BINDIR)'
|
||||
mkdir -p '$(DESTDIR)$(JANET_MANPATH)'
|
||||
cp janet.1 '$(DESTDIR)$(JANET_MANPATH)'
|
||||
cp jpm.1 '$(DESTDIR)$(JANET_MANPATH)'
|
||||
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
||||
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || true
|
||||
|
||||
uninstall:
|
||||
-rm '$(DESTDIR)$(BINDIR)/janet'
|
||||
-rm '$(DESTDIR)$(BINDIR)/jpm'
|
||||
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
-rm -rf '$(DESTDIR)$(LIBDIR)'/libjanet.*
|
||||
-rm '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||
-rm '$(DESTDIR)$(JANET_MANPATH)/janet.1'
|
||||
-rm '$(DESTDIR)$(JANET_MANPATH)/jpm.1'
|
||||
# -rm -rf '$(DESTDIR)$(JANET_PATH)'/* - err on the side of correctness here
|
||||
|
||||
#################
|
||||
##### Other #####
|
||||
#################
|
||||
|
||||
dist: janet-dist.tar.gz
|
||||
format:
|
||||
tools/format.sh
|
||||
|
||||
janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \
|
||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) README.md
|
||||
tar -czvf $@ $^
|
||||
grammar: build/janet.tmLanguage
|
||||
build/janet.tmLanguage: tools/tm_lang_gen.janet $(JANET_TARGET)
|
||||
$(JANET_TARGET) $< > $@
|
||||
|
||||
compile-commands:
|
||||
# Requires pip install copmiledb
|
||||
compiledb make
|
||||
|
||||
clean:
|
||||
-rm $(JANET_TARGET)
|
||||
-rm $(JANET_LIBRARY)
|
||||
-rm ctest/*.o ctest/*.out
|
||||
-rm src/**/*.o src/**/*.bc vgcore.* *.js *.wasm *.html
|
||||
-rm src/**/*.gen.c
|
||||
-rm janet-*.tar.gz
|
||||
-rm -rf build vgcore.* callgrind.*
|
||||
-rm -rf test/install/build test/install/modpath
|
||||
|
||||
install: $(JANET_TARGET)
|
||||
mkdir -p $(BINDIR)
|
||||
cp $(JANET_TARGET) $(BINDIR)/$(JANET_TARGET)
|
||||
mkdir -p $(INCLUDEDIR)
|
||||
cp $(JANET_HEADERS) $(INCLUDEDIR)
|
||||
mkdir -p $(LIBDIR)
|
||||
cp $(JANET_LIBRARY) $(LIBDIR)/$(JANET_LIBRARY)
|
||||
cp janet.1 /usr/local/share/man/man1/
|
||||
mandb
|
||||
$(LDCONFIG)
|
||||
test-install:
|
||||
cd test/install \
|
||||
&& rm -rf build .cache .manifests \
|
||||
&& jpm --verbose build \
|
||||
&& jpm --verbose test \
|
||||
&& build/testexec \
|
||||
&& jpm --verbose quickbin testexec.janet build/testexec2 \
|
||||
&& build/testexec2 \
|
||||
&& mkdir -p modpath \
|
||||
&& jpm --verbose --testdeps --modpath=./modpath install https://github.com/janet-lang/json.git
|
||||
cd test/install && jpm --verbose --test --modpath=./modpath install https://github.com/janet-lang/jhydro.git
|
||||
cd test/install && jpm --verbose --test --modpath=./modpath install https://github.com/janet-lang/path.git
|
||||
cd test/install && jpm --verbose --test --modpath=./modpath install https://github.com/janet-lang/argparse.git
|
||||
|
||||
install-libs: natives
|
||||
mkdir -p $(JANET_PATH)
|
||||
cp -r lib $(JANET_PATH)
|
||||
cp natives/*/*.so $(JANET_PATH)
|
||||
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
|
||||
|
||||
uninstall:
|
||||
-rm $(BINDIR)/$(JANET_TARGET)
|
||||
-rm $(LIBDIR)/$(JANET_LIBRARY)
|
||||
-rm -rf $(INCLUDEDIR)
|
||||
$(LDCONFIG)
|
||||
|
||||
.PHONY: clean install repl debug valgrind test valtest dist install uninstall \
|
||||
$(TEST_PROGRAM_PHONIES) $(TEST_PROGRAM_VALPHONIES)
|
||||
.PHONY: clean install repl debug valgrind test \
|
||||
valtest dist uninstall docs grammar format help compile-commands
|
||||
|
||||
304
README.md
304
README.md
@@ -1,184 +1,250 @@
|
||||
# janet
|
||||
[](https://gitter.im/janet-language/community)
|
||||
|
||||
[](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
|
||||
[](https://travis-ci.org/janet-lang/janet)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/freebsd.yml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/openbsd.yml?)
|
||||
|
||||
[](https://travis-ci.org/bakpakin/janet)
|
||||
[](https://ci.appveyor.com/project/bakpakin/janet)
|
||||
<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 functional and imperative programming language and bytecode interpreter. It is a
|
||||
lisp-like language, but lists are replaced
|
||||
by other data structures (arrays, tables (hash table), struct (immutable hash table), tuples).
|
||||
The language also supports 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
|
||||
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
|
||||
Janet can be embedded in other programs. Try Janet in your browser at
|
||||
[https://janet-lang.org](https://janet-lang.org).
|
||||
|
||||
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.
|
||||
|
||||
For syntax highlighting, there is some preliminary vim syntax highlighting in [janet.vim](https://github.com/bakpakin/janet.vim).
|
||||
Generic lisp syntax highlighting should, however, provide good results.
|
||||
<br>
|
||||
|
||||
## Use Cases
|
||||
|
||||
Janet makes a good system scripting language, or a language to embed in other programs. Think Lua or Guile.
|
||||
Janet makes a good system scripting language, or a language to embed in other programs.
|
||||
It's like Lua and Guile in that regard. It has more built-in functionality and a richer core language than
|
||||
Lua, but smaller than GNU Guile or Python.
|
||||
|
||||
## Features
|
||||
|
||||
* Minimal setup - one binary and you are good to go!
|
||||
* First class closures
|
||||
* First-class closures
|
||||
* Garbage collection
|
||||
* First class green threads (continuations)
|
||||
* Python style generators (implemented as a plain macro)
|
||||
* First-class green threads (continuations)
|
||||
* 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
|
||||
* Macros
|
||||
* Byte code interpreter with an assembly interface, as well as bytecode verification
|
||||
* Tailcall Optimization
|
||||
* Tail call 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
|
||||
* 300+ functions and macros in the core library
|
||||
* Parsing Expression Grammars built into the core library
|
||||
* 400+ functions and macros in the core library
|
||||
* Embedding Janet in other programs
|
||||
* Interactive environment with detailed stack traces
|
||||
|
||||
## Documentation
|
||||
|
||||
API documentation and design documents can be found in the
|
||||
[wiki](https://github.com/bakpakin/janet/wiki). There is an introduction
|
||||
section in the wiki that 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)
|
||||
|
||||
For individual bindings, 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.
|
||||
|
||||
## Source
|
||||
|
||||
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.
|
||||
|
||||
## Building
|
||||
|
||||
### macOS and Unix-like
|
||||
|
||||
The Makefile is non-portable and requires GNU-flavored make.
|
||||
|
||||
```
|
||||
cd somewhere/my/projects/janet
|
||||
make
|
||||
make test
|
||||
make repl
|
||||
```
|
||||
|
||||
Find out more about the available make targets by running `make help`.
|
||||
|
||||
### 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`.
|
||||
|
||||
```
|
||||
cd somewhere/my/projects/janet
|
||||
make CC=gcc-x86
|
||||
make test
|
||||
make repl
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
|
||||
FreeBSD build instructions are the same as the UNIX-like build instructions,
|
||||
but you need `gmake` to compile. Alternatively, install directly from
|
||||
packages, using `pkg install lang/janet`.
|
||||
|
||||
```
|
||||
cd somewhere/my/projects/janet
|
||||
gmake
|
||||
gmake test
|
||||
gmake repl
|
||||
```
|
||||
|
||||
### NetBSD
|
||||
|
||||
NetBSD build instructions are the same as the FreeBSD build instructions.
|
||||
Alternatively, install directly from packages, using `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.
|
||||
4. Run `build_win test` to make sure everything is working.
|
||||
|
||||
To build an `.msi` installer executable, in addition to the above steps, you will have to:
|
||||
|
||||
5. Install, or otherwise add to your PATH the [WiX 3.11 Toolset](https://github.com/wixtoolset/wix3/releases)
|
||||
6. run `build_win dist`
|
||||
|
||||
Now you should have an `.msi`. You can run `build_win install` to install the `.msi`, or execute the file itself.
|
||||
|
||||
### 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 will have syntax packages for the Janet language, though.
|
||||
|
||||
## Installation
|
||||
|
||||
Install a stable version of janet from the [releases page](https://github.com/bakpakin/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.
|
||||
See [the Introduction](https://janet-lang.org/introduction.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
|
||||
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-symbols)` into the repl.
|
||||
by entering the command `(all-bindings)` into the REPL.
|
||||
|
||||
```
|
||||
$ ./janet
|
||||
Janet 0.0.0 alpha Copyright (C) 2017-2018 Calvin Rose
|
||||
$ 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] scripts...
|
||||
janet:3:> (os/exit)
|
||||
$ janet -h
|
||||
usage: build/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 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
|
||||
$
|
||||
-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
|
||||
-r : Enter the REPL after running all scripts
|
||||
-p : Keep on executing if there is a top-level error (persistent)
|
||||
-q : Hide prompt, logo, and REPL output (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
|
||||
-n : Disable ANSI color output in the REPL
|
||||
-l path : Execute code in a file before running the main script
|
||||
-- : Stop handling options
|
||||
```
|
||||
|
||||
## Compiling and Running
|
||||
If installed, you can also run `man janet` and `man jpm` to get usage information.
|
||||
|
||||
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.
|
||||
## Embedding
|
||||
|
||||
### Unix-like
|
||||
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 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.
|
||||
|
||||
On most platforms, use Make to build janet.
|
||||
|
||||
```sh
|
||||
cd somewhere/my/projects/janet
|
||||
make
|
||||
make test
|
||||
```
|
||||
|
||||
After building, run `make install` to install the janet binary and libs.
|
||||
Will install in `/usr/local` by default, see the Makefile to customize.
|
||||
|
||||
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.
|
||||
|
||||
### FreeBSD
|
||||
|
||||
FreeBSD build instructions are the same as the unix-like build instuctions,
|
||||
but you need `gmake` and `gcc` to compile.
|
||||
|
||||
```
|
||||
cd somewhere/my/projects/janet
|
||||
gmake CC=gcc
|
||||
gmake test CC=gcc
|
||||
```
|
||||
|
||||
### 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.
|
||||
4. Run `build_win test` to make sure everything is working.
|
||||
|
||||
### Emscripten
|
||||
|
||||
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 janet.js` 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 much slower in a browser.
|
||||
Building with emscripten on windows is currently unsupported.
|
||||
See the [Embedding Section](https://janet-lang.org/capi/embedding.html) on the website for more information.
|
||||
|
||||
## Examples
|
||||
|
||||
See the examples directory for some example janet code.
|
||||
|
||||
## SQLite bindings
|
||||
## Discussion
|
||||
|
||||
There are some sqlite3 bindings in the directory natives/sqlite3. They serve mostly as a
|
||||
proof of concept external c library. To use, first compile the module with Make.
|
||||
Feel free to ask questions and join the discussion on the [Janet Gitter Channel](https://gitter.im/janet-language/community).
|
||||
Alternatively, check out [the #janet channel on Freenode](https://webchat.freenode.net/)
|
||||
|
||||
```sh
|
||||
make natives
|
||||
```
|
||||
## FAQ
|
||||
|
||||
Next, enter the repl and create a database and a table.
|
||||
### Why is my terminal spitting out junk when I run the REPL?
|
||||
|
||||
```
|
||||
janet:1:> (import natives/sqlite3 :as sql)
|
||||
nil
|
||||
janet:2:> (def db (sql/open "test.db"))
|
||||
<sqlite3.connection 0x5561A138C470>
|
||||
janet:3:> (sql/eval db `CREATE TABLE customers(id INTEGER PRIMARY KEY, name TEXT);`)
|
||||
@[]
|
||||
janet:4:> (sql/eval db `INSERT INTO customers VALUES(:id, :name);` {:name "John" :id 12345})
|
||||
@[]
|
||||
janet:5:> (sql/eval db `SELECT * FROM customers;`)
|
||||
@[{"id" 12345 "name" "John"}]
|
||||
```
|
||||
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` if further issues
|
||||
ensue.
|
||||
|
||||
Finally, close the database connection when done with it.
|
||||
## Why Janet
|
||||
|
||||
```
|
||||
janet:6:> (sql/close db)
|
||||
nil
|
||||
```
|
||||
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">
|
||||
|
||||
42
appveyor.yml
42
appveyor.yml
@@ -1,12 +1,12 @@
|
||||
version: build-{build}
|
||||
clone_folder: c:\projects\janet
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
configuration:
|
||||
- Release
|
||||
- Debug
|
||||
platform:
|
||||
- x64
|
||||
- x86
|
||||
environment:
|
||||
matrix:
|
||||
- arch: Win64
|
||||
@@ -15,31 +15,41 @@ matrix:
|
||||
|
||||
# skip unsupported combinations
|
||||
init:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
|
||||
|
||||
install:
|
||||
- build_win
|
||||
- build_win test
|
||||
- build_win dist
|
||||
|
||||
- set JANET_BUILD=%appveyor_repo_commit:~0,7%
|
||||
- build_win all
|
||||
- refreshenv
|
||||
# We need to reload vcvars after refreshing
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
|
||||
- build_win test-install
|
||||
- set janet_outname=%appveyor_repo_tag_name%
|
||||
- if "%janet_outname%"=="" set /P janet_outname=<build\version.txt
|
||||
build: off
|
||||
|
||||
only_commits:
|
||||
files:
|
||||
- appveyor.yml
|
||||
- src/
|
||||
|
||||
artifacts:
|
||||
- path: dist
|
||||
name: janet-windows
|
||||
- name: janet.c
|
||||
path: dist\janet.c
|
||||
type: File
|
||||
- name: janet.h
|
||||
path: dist\janet.h
|
||||
type: File
|
||||
- name: shell.c
|
||||
path: dist\shell.c
|
||||
type: File
|
||||
- name: "janet-$(janet_outname)-windows-%platform%"
|
||||
path: dist
|
||||
type: Zip
|
||||
- path: "janet-$(janet_outname)-windows-%platform%-installer.msi"
|
||||
type: File
|
||||
|
||||
deploy:
|
||||
description: 'The Janet Programming Language.'
|
||||
provider: GitHub
|
||||
auth_token:
|
||||
secure: lwEXy09qhj2jSH9s1C/KvCkAUqJSma8phFR+0kbsfUc3rVxpNK5uD3z9Md0SjYRx
|
||||
artifact: janet-windows
|
||||
artifact: /(janet|shell).*/
|
||||
draft: true
|
||||
on:
|
||||
APPVEYOR_REPO_TAG: true
|
||||
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 |
BIN
assets/janet-big.png
Normal file
BIN
assets/janet-big.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
assets/janet-the-good-place.gif
Normal file
BIN
assets/janet-the-good-place.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 109 KiB |
BIN
assets/janet-w200.png
Normal file
BIN
assets/janet-w200.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
155
build_win.bat
155
build_win.bat
@@ -13,48 +13,54 @@
|
||||
@if "%1"=="clean" goto CLEAN
|
||||
@if "%1"=="test" goto TEST
|
||||
@if "%1"=="dist" goto DIST
|
||||
@if "%1"=="install" goto INSTALL
|
||||
@if "%1"=="test-install" goto TESTINSTALL
|
||||
@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
|
||||
@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD
|
||||
@set JANET_LINK=link /nologo
|
||||
@set JANET_LINK_STATIC=lib /nologo
|
||||
|
||||
mkdir build
|
||||
mkdir build\core
|
||||
mkdir build\mainclient
|
||||
@rem Add janet build tag
|
||||
if not "%JANET_BUILD%" == "" (
|
||||
@set JANET_COMPILE=%JANET_COMPILE% /DJANET_BUILD="\"%JANET_BUILD%\""
|
||||
)
|
||||
|
||||
@rem Build the xxd tool for generating sources
|
||||
@cl /nologo /c src/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
|
||||
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 Generate the embedded sources
|
||||
@build\xxd.exe src\core\core.janet build\core\core.gen.c janet_gen_core
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@build\xxd.exe src\mainclient\init.janet build\mainclient\init.gen.c janet_gen_init
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@rem Build the generated sources
|
||||
@%JANET_COMPILE% /Fobuild\core\core.gen.obj build\core\core.gen.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
@%JANET_COMPILE% /Fobuild\mainclient\init.gen.obj build\mainclient\init.gen.c
|
||||
@rem Build the bootstrap interpreter
|
||||
for %%f in (src\core\*.c) do (
|
||||
%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
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
)
|
||||
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
|
||||
@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
|
||||
%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 ===
|
||||
@@ -70,7 +76,7 @@ exit /b 1
|
||||
@rem Show help
|
||||
:HELP
|
||||
@echo.
|
||||
@echo Usage: build_windows [subcommand=clean,help,test]
|
||||
@echo Usage: build_windows [subcommand=clean,help,test,dist]
|
||||
@echo.
|
||||
@echo Script to build janet on windows. Must be run from the Visual Studio
|
||||
@echo command prompt.
|
||||
@@ -78,27 +84,108 @@ exit /b 0
|
||||
|
||||
@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
|
||||
janet.exe test\%%f
|
||||
@if errorlevel 1 goto TESTFAIL
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
@rem Build a dist directory
|
||||
:DIST
|
||||
mkdir dist
|
||||
janet.exe tools\gendoc.janet > dist\doc.html
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
copy .\jpm dist\jpm
|
||||
|
||||
@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 Test the installation.
|
||||
:TESTINSTALL
|
||||
pushd test\install
|
||||
call jpm clean
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call jpm test
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call jpm --verbose --modpath=. install https://github.com/janet-lang/json.git
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call build\testexec
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call jpm --verbose quickbin testexec.janet build\testexec2.exe
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call build\testexec2.exe
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call jpm --verbose --test --modpath=. install https://github.com/janet-lang/jhydro.git
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call jpm --verbose --test --modpath=. install https://github.com/janet-lang/path.git
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
call jpm --verbose --test --modpath=. install https://github.com/janet-lang/argparse.git
|
||||
@if errorlevel 1 goto :TESTINSTALLFAIL
|
||||
popd
|
||||
exit /b 0
|
||||
|
||||
:TESTINSTALLFAIL
|
||||
popd
|
||||
goto :TESTFAIL
|
||||
|
||||
@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
|
||||
|
||||
@@ -5,10 +5,14 @@
|
||||
(def solutions @{})
|
||||
(def len (length s))
|
||||
(for k 0 len
|
||||
(put tab s@k k))
|
||||
(put tab (s k) k))
|
||||
(for i 0 len
|
||||
(for j 0 len
|
||||
(def k (get tab (- 0 s@i s@j)))
|
||||
(def k (get tab (- 0 (s i) (s j))))
|
||||
(when (and k (not= k i) (not= k j) (not= i j))
|
||||
(put solutions {i true j true k true} true))))
|
||||
(map keys (keys solution)))
|
||||
(map keys (keys solutions)))
|
||||
|
||||
(def arr @[2 4 1 3 8 7 -3 -1 12 -5 -8])
|
||||
(printf "3sum of %P: " arr)
|
||||
(printf "%P\n" (sum3 arr))
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
# 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)
|
||||
(addi 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
|
||||
|
||||
(defn testn
|
||||
[n]
|
||||
(print "fibasm(" n ") = " (fibasm n)))
|
||||
|
||||
(for i 0 10 (testn i))
|
||||
|
||||
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 ")")])
|
||||
(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))
|
||||
@@ -35,7 +35,13 @@
|
||||
:bright-white 97
|
||||
:bg-bright-white 107})
|
||||
|
||||
(loop [[name color] :in (pairs colormap)]
|
||||
(defglobal (string.slice name 1)
|
||||
(fn color-wrapper [& pieces]
|
||||
(string "\e[" color "m" (apply string pieces) "\e[0m"))))
|
||||
(defn color
|
||||
"Take a string made by concatenating xs and colorize it for an ANSI terminal."
|
||||
[c & xs]
|
||||
(def code (get colormap c))
|
||||
(if (not code) (error (string "color " c " unknown")))
|
||||
(string "\e[" code "m" ;xs "\e[0m"))
|
||||
|
||||
# Print all colors
|
||||
|
||||
(loop [c :keys colormap] (print (color c c)))
|
||||
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)
|
||||
12
examples/evsleep.janet
Normal file
12
examples/evsleep.janet
Normal file
@@ -0,0 +1,12 @@
|
||||
(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)
|
||||
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))
|
||||
@@ -18,12 +18,12 @@
|
||||
(if ,loaded
|
||||
,state
|
||||
(do
|
||||
(:= ,loaded true)
|
||||
(:= ,state (do ;forms)))))))
|
||||
(set ,loaded true)
|
||||
(set ,state (do ,;forms)))))))
|
||||
|
||||
# Use tuples instead of structs to save memory
|
||||
(def HEAD :private 0)
|
||||
(def TAIL :private 1)
|
||||
(def- HEAD 0)
|
||||
(def- TAIL 1)
|
||||
|
||||
(defn empty-seq
|
||||
"The empty sequence."
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
(defn lazy-range
|
||||
"Return a sequence of integers [start, end)."
|
||||
@[start end]
|
||||
[start end &]
|
||||
(if end
|
||||
(if (< start end)
|
||||
(delay (tuple start (lazy-range (+ 1 start) end)))
|
||||
@@ -94,7 +94,7 @@
|
||||
(defn randseq
|
||||
"Return a sequence of random numbers."
|
||||
[]
|
||||
(delay (tuple (math.random) (randseq))))
|
||||
(delay (tuple (math/random) (randseq))))
|
||||
|
||||
(defn take-while
|
||||
"Returns a sequence of values until the predicate is false."
|
||||
@@ -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."
|
||||
@@ -16,7 +16,7 @@
|
||||
(def cell-set (frequencies state))
|
||||
(def neighbor-set (frequencies (mapcat neighbors state)))
|
||||
(seq [coord :keys neighbor-set
|
||||
:let [count neighbor-set@coord]
|
||||
:let [count (get neighbor-set coord)]
|
||||
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
|
||||
coord))
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
|
||||
[state x1 y1 x2 y2]
|
||||
(def cellset @{})
|
||||
(each cell state (:= cellset@cell true))
|
||||
(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 (tuple x y)) "X " ". ")))
|
||||
(file/write stdout (if (get cellset [x y]) "X " ". ")))
|
||||
(print))
|
||||
|
||||
#
|
||||
@@ -40,4 +40,4 @@
|
||||
(for i 0 20
|
||||
(print "generation " i)
|
||||
(draw *state* -7 -7 7 7)
|
||||
(:= *state* (tick *state*)))
|
||||
(set *state* (tick *state*)))
|
||||
|
||||
@@ -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
|
||||
117
examples/numarray/numarray.c
Normal file
117
examples/numarray/numarray.c
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <stdlib.h>
|
||||
#include <janet.h>
|
||||
|
||||
typedef struct {
|
||||
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;
|
||||
return array;
|
||||
}
|
||||
|
||||
static void num_array_deinit(num_array *array) {
|
||||
free(array->data);
|
||||
}
|
||||
|
||||
static int num_array_gc(void *p, size_t s) {
|
||||
(void) s;
|
||||
num_array *array = (num_array *)p;
|
||||
num_array_deinit(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = {
|
||||
"numarray",
|
||||
num_array_gc,
|
||||
NULL,
|
||||
num_array_get,
|
||||
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);
|
||||
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);
|
||||
size_t i;
|
||||
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);
|
||||
double sum = 0;
|
||||
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;
|
||||
if (!janet_checkint(key))
|
||||
janet_panic("expected integer key");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static const JanetMethod methods[] = {
|
||||
{"scale", num_array_scale},
|
||||
{"sum", num_array_sum},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
int num_array_get(void *p, Janet key, Janet *out) {
|
||||
size_t index;
|
||||
num_array *array = (num_array *)p;
|
||||
if (janet_checktype(key, JANET_KEYWORD))
|
||||
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) {
|
||||
return 0;
|
||||
} else {
|
||||
*out = janet_wrap_number(array->data[index]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{
|
||||
"new", num_array_new,
|
||||
"(numarray/new size)\n\n"
|
||||
"Create new numarray"
|
||||
},
|
||||
{
|
||||
"scale", num_array_scale,
|
||||
"(numarray/scale numarray factor)\n\n"
|
||||
"scale numarray by factor"
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
JANET_MODULE_ENTRY(JanetTable *env) {
|
||||
janet_cfuns(env, "numarray", cfuns);
|
||||
}
|
||||
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"])
|
||||
17
examples/numarray/test/numarray_tests.janet
Normal file
17
examples/numarray/test/numarray_tests.janet
Normal file
@@ -0,0 +1,17 @@
|
||||
(import build/numarray)
|
||||
|
||||
(def a (numarray/new 30))
|
||||
(print (get a 20))
|
||||
(print (a 20))
|
||||
|
||||
(put a 5 3.14)
|
||||
(print (a 5))
|
||||
(set (a 5) 100)
|
||||
(print (a 5))
|
||||
|
||||
# (numarray/scale a 5))
|
||||
# ((a :scale) a 5)
|
||||
(:scale a 5)
|
||||
(for i 0 10 (print (a i)))
|
||||
|
||||
(print "sum=" (:sum a))
|
||||
@@ -9,6 +9,8 @@
|
||||
(def len (length list))
|
||||
(for j 0 len
|
||||
(def trial (get list j))
|
||||
(if (zero? (% i trial)) (:= isprime? false)))
|
||||
(if (zero? (% i trial)) (set isprime? false)))
|
||||
(if isprime? (array/push list i)))
|
||||
list)
|
||||
|
||||
(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])))
|
||||
73
examples/tarray.janet
Normal file
73
examples/tarray.janet
Normal file
@@ -0,0 +1,73 @@
|
||||
# naive matrix implementation for testing typed array
|
||||
|
||||
(defn matrix [nrow ncol] {:nrow nrow :ncol ncol :array (tarray/new :float64 (* nrow ncol))})
|
||||
|
||||
(defn matrix/row [mat i]
|
||||
(def {:nrow nrow :ncol ncol :array array} mat)
|
||||
(tarray/new :float64 ncol 1 (* i ncol) array))
|
||||
|
||||
(defn matrix/column [mat j]
|
||||
(def {:nrow nrow :ncol ncol :array array} mat)
|
||||
(tarray/new :float64 nrow ncol j array))
|
||||
|
||||
(defn matrix/set [mat i j value]
|
||||
(def {:nrow nrow :ncol ncol :array array} mat)
|
||||
(set (array (+ (* i ncol) j)) value))
|
||||
|
||||
(defn matrix/get [mat i j value]
|
||||
(def {:nrow nrow :ncol ncol :array array} mat)
|
||||
(array (+ (* i ncol) j)))
|
||||
|
||||
|
||||
# other variants to test rows and cols views
|
||||
|
||||
(defn matrix/set* [mat i j value]
|
||||
(set ((matrix/row mat i) j) value))
|
||||
|
||||
(defn matrix/set** [mat i j value]
|
||||
(set ((matrix/column mat j) i) value))
|
||||
|
||||
|
||||
(defn matrix/get* [mat i j value]
|
||||
((matrix/row mat i) j))
|
||||
|
||||
(defn matrix/get** [mat i j value]
|
||||
((matrix/column mat j) i))
|
||||
|
||||
|
||||
(defn tarray/print [arr]
|
||||
(def size (tarray/length arr))
|
||||
(prinf "[%2i]" size)
|
||||
(for i 0 size
|
||||
(prinf " %+6.3f " (arr i)))
|
||||
(print))
|
||||
|
||||
(defn matrix/print [mat]
|
||||
(def {:nrow nrow :ncol ncol :array tarray} mat)
|
||||
(printf "matrix %iX%i %p" nrow ncol tarray)
|
||||
(for i 0 nrow
|
||||
(tarray/print (matrix/row mat i))))
|
||||
|
||||
|
||||
(def nr 5)
|
||||
(def nc 4)
|
||||
(def A (matrix nr nc))
|
||||
|
||||
(loop (i :range (0 nr) j :range (0 nc))
|
||||
(matrix/set A i j i))
|
||||
(matrix/print A)
|
||||
|
||||
(loop (i :range (0 nr) j :range (0 nc))
|
||||
(matrix/set* A i j i))
|
||||
(matrix/print A)
|
||||
|
||||
(loop (i :range (0 nr) j :range (0 nc))
|
||||
(matrix/set** A i j i))
|
||||
(matrix/print A)
|
||||
|
||||
|
||||
(printf "properties:\n%p" (tarray/properties (A :array)))
|
||||
(for i 0 nr
|
||||
(printf "row properties:[%i]\n%p" i (tarray/properties (matrix/row A i))))
|
||||
(for i 0 nc
|
||||
(printf "col properties:[%i]\n%p" i (tarray/properties (matrix/column A i))))
|
||||
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"))))
|
||||
68
examples/threads.janet
Normal file
68
examples/threads.janet
Normal file
@@ -0,0 +1,68 @@
|
||||
(defn worker-main
|
||||
"Sends 11 messages back to parent"
|
||||
[parent]
|
||||
(def name (thread/receive))
|
||||
(def interval (thread/receive))
|
||||
(for i 0 10
|
||||
(os/sleep interval)
|
||||
(:send parent (string/format "thread %s wakeup no. %d" name i)))
|
||||
(:send parent name))
|
||||
|
||||
(defn make-worker
|
||||
[name interval]
|
||||
(-> (thread/new worker-main)
|
||||
(:send name)
|
||||
(:send interval)))
|
||||
|
||||
(def bob (make-worker "bob" 0.02))
|
||||
(def joe (make-worker "joe" 0.03))
|
||||
(def sam (make-worker "sam" 0.05))
|
||||
|
||||
# Receive out of order
|
||||
(for i 0 33
|
||||
(print (thread/receive)))
|
||||
|
||||
#
|
||||
# Recursive Thread Tree - should pause for a bit, and then print a cool zigzag.
|
||||
#
|
||||
|
||||
(def rng (math/rng (os/cryptorand 16)))
|
||||
|
||||
(defn choose [& xs]
|
||||
(in xs (:int rng (length xs))))
|
||||
|
||||
(defn worker-tree
|
||||
[parent]
|
||||
(def name (thread/receive))
|
||||
(def depth (thread/receive))
|
||||
(if (< depth 5)
|
||||
(do
|
||||
(defn subtree []
|
||||
(-> (thread/new worker-tree)
|
||||
(:send (string name "/" (choose "bob" "marley" "harry" "suki" "anna" "yu")))
|
||||
(:send (inc depth))))
|
||||
(let [l (subtree)
|
||||
r (subtree)
|
||||
lrep (thread/receive)
|
||||
rrep (thread/receive)]
|
||||
(:send parent [name ;lrep ;rrep])))
|
||||
(do
|
||||
(:send parent [name]))))
|
||||
|
||||
(-> (thread/new worker-tree) (:send "adam") (:send 0))
|
||||
(def lines (thread/receive))
|
||||
(map print lines)
|
||||
|
||||
#
|
||||
# Receive timeout
|
||||
#
|
||||
|
||||
(def slow (make-worker "slow-loras" 0.5))
|
||||
(for i 0 50
|
||||
(try
|
||||
(let [msg (thread/receive 0.1)]
|
||||
(print "\n" msg))
|
||||
([err] (prin ".") (:flush stdout))))
|
||||
|
||||
(print "\ndone timing, timeouts ending.")
|
||||
(try (while true (print (thread/receive))) ([err] (print "done")))
|
||||
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 repl, and then:
|
||||
#
|
||||
# (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 f (file/popen (string "curl " url)))
|
||||
(def res (dofile f :source url ;args))
|
||||
(try (file/close f) ([err] nil))
|
||||
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)
|
||||
231
janet.1
231
janet.1
@@ -1,26 +1,142 @@
|
||||
.TH JANET 1
|
||||
.SH NAME
|
||||
janet \- run the janet language abstract machine
|
||||
janet \- run the Janet language abstract machine
|
||||
.SH SYNOPSIS
|
||||
.B janet
|
||||
[\fB\-hvsrp\fR]
|
||||
[\fB\-e\fR \fIJANET SOURCE\fR]
|
||||
[\fB\-hvsrpnqk\fR]
|
||||
[\fB\-e\fR \fISOURCE\fR]
|
||||
[\fB\-l\fR \fIMODULE\fR]
|
||||
[\fB\-m\fR \fIPATH\fR]
|
||||
[\fB\-c\fR \fIMODULE JIMAGE\fR]
|
||||
[\fB\-\-\fR]
|
||||
.IR files ...
|
||||
.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
|
||||
Janet is a functional and imperative programming language and bytecode interpreter.
|
||||
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.
|
||||
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.
|
||||
|
||||
Implemented in mostly standard C99, janet runs on Windows, Linux and macOS.
|
||||
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
|
||||
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
|
||||
@@ -37,37 +153,90 @@ Shows the version text and exits immediately.
|
||||
|
||||
.TP
|
||||
.BR \-s
|
||||
Read raw input from stdin, such as from a pipe without printing a prompt.
|
||||
Read raw input from stdin and forgo prompt history and other readline-like features.
|
||||
|
||||
.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 \-p
|
||||
Turn on the persistent flag. By default, when janet is executing commands from a file and encounters an error,
|
||||
it will immediately exit after printing the error message. In persistent mode, janet will keep executing commands
|
||||
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
|
||||
.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 \-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 \-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,
|
||||
it will immediately exit after printing the error message. In persistent mode, Janet will keep executing commands
|
||||
after an error. Persistent mode can be good for debugging and testing.
|
||||
|
||||
.TP
|
||||
.BR \-q
|
||||
Hide the logo in the repl.
|
||||
|
||||
.TP
|
||||
.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 \-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 \-\-
|
||||
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
|
||||
|
||||
.B JANET_PATH
|
||||
.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 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
|
||||
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
|
||||
|
||||
.SH AUTHOR
|
||||
|
||||
1
janet_win.rc
Normal file
1
janet_win.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_MYICON ICON "assets\icon.ico"
|
||||
269
jpm.1
Normal file
269
jpm.1
Normal file
@@ -0,0 +1,269 @@
|
||||
.TH JPM 1
|
||||
.SH NAME
|
||||
jpm \- the Janet Project Manager, a build tool for Janet
|
||||
.SH SYNOPSIS
|
||||
.B jpm
|
||||
[\fB\-\-flag ...\fR]
|
||||
[\fB\-\-option=value ...\fR]
|
||||
.IR command
|
||||
.IR args ...
|
||||
.SH DESCRIPTION
|
||||
jpm is the build tool that ships with a standard Janet install. It is
|
||||
used for building Janet projects, installing dependencies, installing
|
||||
projects, building native modules, and exporting your Janet project to a
|
||||
standalone executable. Although not required for working with Janet, it
|
||||
removes much of the boilerplate with installing dependencies and
|
||||
building native modules. jpm requires only Janet to run, and uses git
|
||||
to install dependencies (jpm will work without git installed).
|
||||
.SH DOCUMENTATION
|
||||
|
||||
jpm has several subcommands, each used for managing either a single Janet project or
|
||||
all Janet modules installed on the system. Global commands, those that manage modules
|
||||
at the system level, do things like install and uninstall packages, as well as clear the cache.
|
||||
More interesting are the local commands. For more information on jpm usage, see https://janet-lang.org/docs/index.html
|
||||
|
||||
.SH FLAGS
|
||||
|
||||
.TP
|
||||
.BR \-\-nocolor
|
||||
Disable color in the jpm debug repl.
|
||||
|
||||
.TP
|
||||
.BR \-\-verbose
|
||||
Print detailed messages of what jpm is doing, including compilation commands and other shell commands.
|
||||
|
||||
.TP
|
||||
.BR \-\-test
|
||||
If passed to jpm install, runs tests before installing. Will run tests recursively on dependencies.
|
||||
|
||||
.TP
|
||||
.BR \-\-offline
|
||||
Prevents jpm from going to network to get dependencies - all dependencies should be in the cache or this command will fail.
|
||||
Use this flag with the deps and update-pkgs subcommands. This is not a surefire way to prevent a build script from accessing
|
||||
the network, for example, a build script that invokes curl will still have network access.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.BR \-\-modpath=/some/path
|
||||
Set the path to install modules to. Defaults to $JANET_MODPATH, $JANET_PATH, or (dyn :syspath) in that order. You most likely don't need this.
|
||||
|
||||
.TP
|
||||
.BR \-\-headerpath=/some/path
|
||||
Set the path the jpm will include when building C source code. This lets
|
||||
you specify the location of janet.h and janetconf.h on your system. On a
|
||||
normal install, this option is not needed.
|
||||
|
||||
.TP
|
||||
.BR \-\-binpath=/some/path
|
||||
Set the path that jpm will install scripts and standalone executables to. Executables
|
||||
defined via declare-execuatble or scripts declared via declare-binscript will be installed
|
||||
here when jpm install is run. Defaults to $JANET_BINPATH, or a reasonable default for the system.
|
||||
See JANET_BINPATH for more.
|
||||
|
||||
.TP
|
||||
.BR \-\-libpath=/some/path
|
||||
Sets the path jpm will use to look for libjanet.a for building standalone executables. libjanet.so
|
||||
is \fBnot\fR used for building native modules or standalone executables, only
|
||||
for linking into applications that want to embed janet as a dynamic module.
|
||||
Linking statically might be a better idea, even in that case. Defaults to
|
||||
$JANET_LIBPATH, or a reasonable default. See JANET_LIBPATH for more.
|
||||
|
||||
.TP
|
||||
.BR \-\-compiler=$CC
|
||||
Sets the C compiler used for compiling native modules and standalone executables. Defaults
|
||||
to cc.
|
||||
|
||||
.TP
|
||||
.BR \-\-cpp\-compiler=$CXX
|
||||
Sets the C++ compiler used for compiling native modules and standalone executables. Defaults
|
||||
to c++..
|
||||
|
||||
.TP
|
||||
.BR \-\-linker
|
||||
Sets the linker used to create native modules and executables. Only used on windows, where
|
||||
it defaults to link.exe.
|
||||
|
||||
.TP
|
||||
.BR \-\-pkglist=https://github.com/janet-lang/pkgs.git
|
||||
Sets the git repository for the package listing used to resolve shorthand package names.
|
||||
|
||||
.TP
|
||||
.BR \-\-archiver=$AR
|
||||
Sets the command used for creating static libraries, use for linking into the standalone executable.
|
||||
Native modules are compiled twice, once a normal native module (shared object), and once as an
|
||||
archive. Defaults to ar.
|
||||
|
||||
.SH COMMANDS
|
||||
.TP
|
||||
.BR help
|
||||
Shows the usage text and exits immediately.
|
||||
|
||||
.TP
|
||||
.BR build
|
||||
Builds all artifacts specified in the project.janet file in the current directory. Artifacts will
|
||||
be created in the ./build/ directory.
|
||||
|
||||
.TP
|
||||
.BR install\ [\fBrepo...\fR]
|
||||
When run with no arguments, installs all installable artifacts in the current project to
|
||||
the current JANET_MODPATH for modules and JANET_BINPATH for executables and scripts. Can also
|
||||
take an optional git repository URL and will install all artifacts in that repository instead.
|
||||
When run with an argument, install does not need to be run from a jpm project directory. Will also
|
||||
install multiple dependencies in one command.
|
||||
|
||||
.TP
|
||||
.BR uninstall\ [\fBname...\fR]
|
||||
Uninstall a project installed with install. uninstall expects the name of the project, not the
|
||||
repository url, path to installed file, or executable name. The name of the project must be specified
|
||||
at the top of the project.janet file in the declare-project form. If no name is given, uninstalls
|
||||
the current project if installed. Will also uninstall multiple packages in one command.
|
||||
|
||||
.TP
|
||||
.BR clean
|
||||
Remove all artifacts created by jpm. This just deletes the build folder.
|
||||
|
||||
.TP
|
||||
.BR test
|
||||
Runs jpm tests. jpm will run all janet source files in the test directory as tests. A test
|
||||
is considered failing if it exits with a non-zero exit code.
|
||||
|
||||
.TP
|
||||
.BR deps
|
||||
Install all dependencies that this project requires recursively. jpm does not
|
||||
resolve dependency issues, like conflicting versions of the same module are required, or
|
||||
different modules with the same name. Dependencies are installed with git, so deps requires
|
||||
git to be on the PATH.
|
||||
|
||||
.TP
|
||||
.BR clear-cache
|
||||
jpm caches git repositories that are needed to install modules from a remote
|
||||
source in a global cache ($JANET_PATH/.cache). If these dependencies are out of
|
||||
date or too large, clear-cache will remove the cache and jpm will rebuild it
|
||||
when needed. clear-cache is a global command, so a project.janet is not
|
||||
required.
|
||||
|
||||
.TP
|
||||
.BR list-installed
|
||||
List all installed packages in the current syspath.
|
||||
|
||||
.TP
|
||||
.BR list-pkgs\ [\fBsearch\fR]
|
||||
List all package aliases in the current package listing that contain the given search string.
|
||||
If no search string is given, prints the entire listing.
|
||||
|
||||
.TP
|
||||
.BR clear-manifest
|
||||
jpm creates a manifest directory that contains a list of all installed files.
|
||||
By deleting this directory, jpm will think that nothing is installed and will
|
||||
try reinstalling everything on the jpm deps or jpm load-lockfile commands. Be careful with
|
||||
this command, as it may leave extra files on your system and shouldn't be needed
|
||||
most of the time in a healthy install.
|
||||
|
||||
.TP
|
||||
.BR run\ [\fBrule\fR]
|
||||
Run a given rule defined in project.janet. Project definitions files (project.janet) usually
|
||||
contain a few artifact declarations, which set up rules that jpm can then resolve, or execute.
|
||||
A project.janet can also create custom rules to create arbitrary files or run arbitrary code, much
|
||||
like make. run will run a single rule or build a single file.
|
||||
|
||||
.TP
|
||||
.BR rules
|
||||
List all rules that can be run via run. This is useful for exploring rules in the project.
|
||||
|
||||
.TP
|
||||
.BR rule-tree\ [\fBroot\fR]\ [\fBdepth\fR]
|
||||
Show rule dependency tree in a pretty format. Optionally provide a rule to use as the tree
|
||||
root, as well as a max depth to print. By default, prints the full tree for all rules. This
|
||||
can be quite long, so it is recommended to give a root rule.
|
||||
|
||||
.TP
|
||||
.BR show-paths
|
||||
Show all of the paths used when installing and building artifacts.
|
||||
|
||||
.TP
|
||||
.BR update-pkgs
|
||||
Update the package listing by installing the 'pkgs' package. Same as jpm install pkgs
|
||||
|
||||
.TP
|
||||
.BR quickbin\ [\fBentry\fR]\ [\fBexecutable\fR]
|
||||
Create a standalone, statically linked executable from a Janet source file that contains a main function.
|
||||
The main function is the entry point of the program and will receive command line arguments
|
||||
as function arguments. The entry file can import other modules, including native C modules, and
|
||||
jpm will attempt to include the dependencies into the generated executable.
|
||||
|
||||
.TP
|
||||
.BR debug-repl
|
||||
Load the current project.janet file and start a repl in it's environment. This lets a user better
|
||||
debug the project file, as well as run rules manually.
|
||||
|
||||
.TP
|
||||
.BR make-lockfile\ [\fBfilename\fR]
|
||||
Create a lockfile. A lockfile is a record that describes what dependencies were installed at the
|
||||
time of the lockfile's creation, including exact versions. A lockfile can then be later used
|
||||
to set up that environment on a different machine via load-lockfile. By default, the lockfile
|
||||
is created at lockfile.jdn, although any path can be used.
|
||||
|
||||
.TP
|
||||
.BR load-lockfile\ [\fBfilename\fR]
|
||||
Install dependencies from a lockfile previously created with make-lockfile. By default, will look
|
||||
for a lockfile at lockfile.jdn, although any path can be used.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
|
||||
.B JANET_PATH
|
||||
.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
|
||||
the default location set at compile time, which can be determined with (dyn :syspath)
|
||||
.RE
|
||||
|
||||
.B JANET_MODPATH
|
||||
.RS
|
||||
The location that jpm will use to install libraries to. Defaults to JANET_PATH, but you could
|
||||
set this to a different directory if you want to. Doing so would let you import Janet modules
|
||||
on the normal system path (JANET_PATH or (dyn :syspath)), but install to a different directory. It is also a more reliable way to install.
|
||||
This variable is overwritten by the --modpath=/some/path if it is provided.
|
||||
.RE
|
||||
|
||||
.B JANET_HEADERPATH
|
||||
.RS
|
||||
The location that jpm will look for janet header files (janet.h and janetconf.h) that are used
|
||||
to build native modules and standalone executables. If janet.h and janetconf.h are available as
|
||||
default includes on your system, this value is not required. If not provided, will default to
|
||||
<jpm script location>/../include/janet. The --headerpath=/some/path option will override this
|
||||
variable.
|
||||
.RE
|
||||
|
||||
.B JANET_LIBPATH
|
||||
.RS
|
||||
Similar to JANET_HEADERPATH, this path is where jpm will look for
|
||||
libjanet.a for creating standalone executables. This does not need to be
|
||||
set on a normal install.
|
||||
If not provided, this will default to <jpm script location>/../lib.
|
||||
The --libpath=/some/path option will override this variable.
|
||||
.RE
|
||||
|
||||
.B JANET_BINPATH
|
||||
.RS
|
||||
The directory where jpm will install binary scripts and executables to.
|
||||
Defaults to
|
||||
(dyn :syspath)/bin
|
||||
The --binpath=/some/path will override this variable.
|
||||
.RE
|
||||
|
||||
.B JANET_PKGLIST
|
||||
.RS
|
||||
The git repository URL that contains a listing of packages. This allows installing packages with shortnames, which
|
||||
is mostly a convenience. However, package dependencies can use short names, package listings
|
||||
can be used to choose a particular set of dependency versions for a whole project.
|
||||
.RE
|
||||
|
||||
.B JANET_GIT
|
||||
.RS
|
||||
An optional path to a git executable to use to clone git dependencies. By default, uses "git" on the current $PATH. You shouldn't need to set this
|
||||
if you have a normal install of git.
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Written by Calvin Rose <calsrose@gmail.com>
|
||||
271
meson.build
Normal file
271
meson.build
Normal file
@@ -0,0 +1,271 @@
|
||||
# Copyright (c) 2020 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', 'b_lundef=false', 'default_library=both'],
|
||||
version : '1.15.2')
|
||||
|
||||
# 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)
|
||||
thread_dep = dependency('threads')
|
||||
|
||||
# Link options
|
||||
if 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'))
|
||||
conf.set('JANET_REDUCED_OS', get_option('reduced_os'))
|
||||
conf.set('JANET_NO_TYPED_ARRAY', not get_option('typed_array'))
|
||||
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_EPOLL', get_option('epoll'))
|
||||
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/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/string.c',
|
||||
'src/core/strtod.c',
|
||||
'src/core/struct.c',
|
||||
'src/core/symcache.c',
|
||||
'src/core/table.c',
|
||||
'src/core/thread.c',
|
||||
'src/core/tuple.c',
|
||||
'src/core/typedarray.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],
|
||||
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_HEADERPATH', header_path
|
||||
])
|
||||
|
||||
libjanet = library('janet', janetc,
|
||||
include_directories : incdir,
|
||||
dependencies : [m_dep, dl_dep, thread_dep],
|
||||
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 : [m_dep, dl_dep, thread_dep],
|
||||
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 : [m_dep, dl_dep, thread_dep],
|
||||
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/suite0000.janet',
|
||||
'test/suite0001.janet',
|
||||
'test/suite0002.janet',
|
||||
'test/suite0003.janet',
|
||||
'test/suite0004.janet',
|
||||
'test/suite0005.janet',
|
||||
'test/suite0006.janet',
|
||||
'test/suite0007.janet',
|
||||
'test/suite0008.janet',
|
||||
'test/suite0009.janet',
|
||||
'test/suite0010.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,
|
||||
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@'])
|
||||
if get_option('peg') and not get_option('reduced_os') and get_option('processes')
|
||||
install_man('jpm.1')
|
||||
patched_jpm = custom_target('patched-jpm',
|
||||
input : ['tools/patch-jpm.janet', 'jpm'],
|
||||
install : true,
|
||||
install_dir : get_option('bindir'),
|
||||
build_by_default : true,
|
||||
output : ['jpm'],
|
||||
command : [janet_nativeclient, '@INPUT@', '@OUTPUT@',
|
||||
'--binpath=' + join_paths(get_option('prefix'), get_option('bindir')),
|
||||
'--libpath=' + join_paths(get_option('prefix'), get_option('libdir')),
|
||||
'--headerpath=' + join_paths(get_option('prefix'), get_option('includedir'))])
|
||||
endif
|
||||
28
meson_options.txt
Normal file
28
meson_options.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
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('typed_array', 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('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,44 +0,0 @@
|
||||
# Copyright (c) 2018 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.
|
||||
|
||||
CFLAGS:=-std=c99 -Wall -Wextra -O2 -shared -fpic
|
||||
CFLAGS=-std=c99 -Wall -Wextra -I../../src/include -O2 -shared -fpic
|
||||
OBJECTS:=json.o
|
||||
TARGET:=json.so
|
||||
|
||||
# MacOS specifics
|
||||
UNAME:=$(shell uname -s)
|
||||
ifeq ($(UNAME), Darwin)
|
||||
CFLAGS:=$(CFLAGS) -undefined dynamic_lookup
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
clean:
|
||||
rm $(OBJECTS)
|
||||
rm $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
@@ -1,25 +0,0 @@
|
||||
@rem Generated batch script, run in 'Visual Studio Developer Prompt'
|
||||
|
||||
@rem
|
||||
|
||||
@echo off
|
||||
|
||||
cl /nologo /I..\..\src\include /c /O2 /W3 json.c
|
||||
@if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
link /nologo /dll ..\..\janet.lib /out:json.dll *.obj
|
||||
if errorlevel 1 goto :BUILDFAIL
|
||||
|
||||
@echo .
|
||||
@echo ======
|
||||
@echo Build Succeeded.
|
||||
@echo =====
|
||||
exit /b 0
|
||||
|
||||
:BUILDFAIL
|
||||
@echo .
|
||||
@echo =====
|
||||
@echo BUILD FAILED. See Output For Details.
|
||||
@echo =====
|
||||
@echo .
|
||||
exit /b 1
|
||||
@@ -1,605 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*****************/
|
||||
/* JSON Decoding */
|
||||
/*****************/
|
||||
|
||||
/* Check if a character is whitespace */
|
||||
static int white(uint8_t c) {
|
||||
return c == '\t' || c == '\n' || c == ' ' || c == '\r';
|
||||
}
|
||||
|
||||
/* Skip whitespace */
|
||||
static void skipwhite(const char **p) {
|
||||
const char *cp = *p;
|
||||
for (;;) {
|
||||
if (white(*cp))
|
||||
cp++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*p = cp;
|
||||
}
|
||||
|
||||
/* Get a hex digit value */
|
||||
static int hexdig(char dig) {
|
||||
if (dig >= '0' && dig <= '9')
|
||||
return dig - '0';
|
||||
if (dig >= 'a' && dig <= 'f')
|
||||
return 10 + dig - 'a';
|
||||
if (dig >= 'A' && dig <= 'F')
|
||||
return 10 + dig - 'A';
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the hex value for a unicode escape */
|
||||
static const char *decode_utf16_escape(const char *p, uint32_t *outpoint) {
|
||||
if (!p[0] || !p[1] || !p[2] || !p[3])
|
||||
return "unexpected end of source";
|
||||
int d1 = hexdig(p[0]);
|
||||
int d2 = hexdig(p[1]);
|
||||
int d3 = hexdig(p[2]);
|
||||
int d4 = hexdig(p[3]);
|
||||
if (d1 < 0 || d2 < 0 || d3 < 0 || d4 < 0)
|
||||
return "invalid hex digit";
|
||||
*outpoint = d4 | (d3 << 4) | (d2 << 8) | (d1 << 12);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse a string. Also handles the conversion of utf-16 to
|
||||
* utf-8. */
|
||||
static const char *decode_string(const char **p, Janet *out) {
|
||||
JanetBuffer *buffer = janet_buffer(0);
|
||||
const char *cp = *p;
|
||||
while (*cp != '"') {
|
||||
uint8_t b = (uint8_t) *cp;
|
||||
if (b < 32) return "invalid character in string";
|
||||
if (b == '\\') {
|
||||
cp++;
|
||||
switch(*cp) {
|
||||
default:
|
||||
return "unknown string escape";
|
||||
case 'b':
|
||||
b = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
b = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
b = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
b = '\r';
|
||||
break;
|
||||
case 't':
|
||||
b = '\t';
|
||||
break;
|
||||
case '"':
|
||||
b = '"';
|
||||
break;
|
||||
case '\\':
|
||||
b = '\\';
|
||||
break;
|
||||
case 'u':
|
||||
{
|
||||
/* Get codepoint and check for surrogate pair */
|
||||
uint32_t codepoint;
|
||||
const char *err = decode_utf16_escape(cp + 1, &codepoint);
|
||||
if (err) return err;
|
||||
if (codepoint >= 0xDC00 && codepoint <= 0xDFFF) {
|
||||
return "unexpected utf-16 low surrogate";
|
||||
} else if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
||||
if (cp[5] != '\\') return "expected utf-16 low surrogate pair";
|
||||
if (cp[6] != 'u') return "expected utf-16 low surrogate pair";
|
||||
uint32_t lowsur;
|
||||
const char *err = decode_utf16_escape(cp + 7, &lowsur);
|
||||
if (err) return err;
|
||||
if (lowsur < 0xDC00 || lowsur > 0xDFFF)
|
||||
return "expected utf-16 low surrogate pair";
|
||||
codepoint = ((codepoint - 0xD800) << 10) +
|
||||
(lowsur - 0xDC00) + 0x10000;
|
||||
cp += 11;
|
||||
} else {
|
||||
cp += 5;
|
||||
}
|
||||
/* Write codepoint */
|
||||
if (codepoint <= 0x7F) {
|
||||
janet_buffer_push_u8(buffer, codepoint);
|
||||
} else if (codepoint <= 0x7FF) {
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 6) & 0x1F) | 0xC0);
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 0) & 0x3F) | 0x80);
|
||||
} else if (codepoint <= 0xFFFF) {
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 12) & 0x0F) | 0xE0);
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 6) & 0x3F) | 0x80);
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 0) & 0x3F) | 0x80);
|
||||
} else {
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 18) & 0x07) | 0xF0);
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 12) & 0x3F) | 0x80);
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 6) & 0x3F) | 0x80);
|
||||
janet_buffer_push_u8(buffer, ((codepoint >> 0) & 0x3F) | 0x80);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
janet_buffer_push_u8(buffer, b);
|
||||
cp++;
|
||||
}
|
||||
*out = janet_stringv(buffer->data, buffer->count);
|
||||
*p = cp + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *decode_one(const char **p, Janet *out, int depth) {
|
||||
|
||||
/* Prevent stack overflow */
|
||||
if (depth > JANET_RECURSION_GUARD) goto recurdepth;
|
||||
|
||||
/* Skip leading whitepspace */
|
||||
skipwhite(p);
|
||||
|
||||
/* Main switch */
|
||||
switch (**p) {
|
||||
default:
|
||||
goto badchar;
|
||||
case '\0':
|
||||
goto eos;
|
||||
/* Numbers */
|
||||
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
||||
case '5': case '6': case '7' : case '8': case '9':
|
||||
{
|
||||
errno = 0;
|
||||
char *end = NULL;
|
||||
double x = strtod(*p, &end);
|
||||
if (end == *p) goto badnum;
|
||||
*p = end;
|
||||
*out = janet_wrap_real(x);
|
||||
break;
|
||||
}
|
||||
/* false, null, true */
|
||||
case 'f':
|
||||
{
|
||||
const char *cp = *p;
|
||||
if (cp[1] != 'a' || cp[2] != 'l' || cp[3] != 's' || cp[4] != 'e')
|
||||
goto badident;
|
||||
*out = janet_wrap_false();
|
||||
*p = cp + 5;
|
||||
break;
|
||||
}
|
||||
case 'n':
|
||||
{
|
||||
const char *cp = *p;
|
||||
|
||||
if (cp[1] != 'u' || cp[2] != 'l' || cp[3] != 'l')
|
||||
goto badident;
|
||||
*out = janet_wrap_nil();
|
||||
*p = cp + 4;
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
{
|
||||
const char *cp = *p;
|
||||
if (cp[1] != 'r' || cp[2] != 'u' || cp[3] != 'e')
|
||||
goto badident;
|
||||
*out = janet_wrap_true();
|
||||
*p = cp + 4;
|
||||
break;
|
||||
}
|
||||
/* String */
|
||||
case '"':
|
||||
{
|
||||
const char *cp = *p + 1;
|
||||
const char *start = cp;
|
||||
while (*cp >= 32 && *cp != '"' && *cp != '\\')
|
||||
cp++;
|
||||
/* Only use a buffer for strings with escapes, else just copy
|
||||
* memory from source */
|
||||
if (*cp == '\\') {
|
||||
*p = *p + 1;
|
||||
const char *err = decode_string(p, out);
|
||||
if (err) return err;
|
||||
break;
|
||||
}
|
||||
if (*cp != '"') goto badchar;
|
||||
*p = cp + 1;
|
||||
*out = janet_stringv((const uint8_t *)start, cp - start);
|
||||
break;
|
||||
}
|
||||
/* Array */
|
||||
case '[':
|
||||
{
|
||||
*p = *p + 1;
|
||||
JanetArray *array = janet_array(0);
|
||||
const char *err;
|
||||
Janet subval;
|
||||
skipwhite(p);
|
||||
while (**p != ']') {
|
||||
err = decode_one(p, &subval, depth + 1);
|
||||
if (err) return err;
|
||||
janet_array_push(array, subval);
|
||||
skipwhite(p);
|
||||
if (**p == ']') break;
|
||||
if (**p != ',') goto wantcomma;
|
||||
*p = *p + 1;
|
||||
}
|
||||
*p = *p + 1;
|
||||
*out = janet_wrap_array(array);
|
||||
}
|
||||
break;
|
||||
/* Object */
|
||||
case '{':
|
||||
{
|
||||
*p = *p + 1;
|
||||
JanetTable *table = janet_table(0);
|
||||
const char *err;
|
||||
Janet subkey, subval;
|
||||
skipwhite(p);
|
||||
while (**p != '}') {
|
||||
skipwhite(p);
|
||||
if (**p != '"') goto wantstring;
|
||||
err = decode_one(p, &subkey, depth + 1);
|
||||
if (err) return err;
|
||||
skipwhite(p);
|
||||
if (**p != ':') goto wantcolon;
|
||||
*p = *p + 1;
|
||||
err = decode_one(p, &subval, depth + 1);
|
||||
if (err) return err;
|
||||
janet_table_put(table, subkey, subval);
|
||||
skipwhite(p);
|
||||
if (**p == '}') break;
|
||||
if (**p != ',') goto wantcomma;
|
||||
*p = *p + 1;
|
||||
}
|
||||
*p = *p + 1;
|
||||
*out = janet_wrap_table(table);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Good return */
|
||||
return NULL;
|
||||
|
||||
/* Errors */
|
||||
recurdepth:
|
||||
return "recured too deeply";
|
||||
eos:
|
||||
return "unexpected end of source";
|
||||
badident:
|
||||
return "bad identifier";
|
||||
badnum:
|
||||
return "bad number";
|
||||
wantcomma:
|
||||
return "expected comma";
|
||||
wantcolon:
|
||||
return "expected colon";
|
||||
badchar:
|
||||
return "unexpected character";
|
||||
wantstring:
|
||||
return "expected json string";
|
||||
}
|
||||
|
||||
static int json_decode(JanetArgs args) {
|
||||
Janet ret;
|
||||
JANET_FIXARITY(args, 1);
|
||||
const char *err;
|
||||
const char *start;
|
||||
const char *p;
|
||||
if (janet_checktype(args.v[0], JANET_BUFFER)) {
|
||||
JanetBuffer *buffer = janet_unwrap_buffer(args.v[0]);
|
||||
/* Ensure 0 padded */
|
||||
janet_buffer_push_u8(buffer, 0);
|
||||
start = p = (const char *)buffer->data;
|
||||
err = decode_one(&p, &ret, 0);
|
||||
buffer->count--;
|
||||
} else {
|
||||
const uint8_t *bytes;
|
||||
int32_t len;
|
||||
JANET_ARG_BYTES(bytes, len, args, 0);
|
||||
start = p = (const char *)bytes;
|
||||
err = decode_one(&p, &ret, 0);
|
||||
}
|
||||
/* Check trailing values */
|
||||
if (!err) {
|
||||
skipwhite(&p);
|
||||
if (*p)
|
||||
err = "unexpected extra token";
|
||||
}
|
||||
if (err) {
|
||||
JANET_THROWV(args, janet_wrap_string(janet_formatc(
|
||||
"decode error at postion %d: %s",
|
||||
p - start,
|
||||
err)));
|
||||
}
|
||||
JANET_RETURN(args, ret);
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* JSON Encoding */
|
||||
/*****************/
|
||||
|
||||
typedef struct {
|
||||
JanetBuffer *buffer;
|
||||
int32_t indent;
|
||||
const uint8_t *tab;
|
||||
const uint8_t *newline;
|
||||
int32_t tablen;
|
||||
int32_t newlinelen;
|
||||
} Encoder;
|
||||
|
||||
static const char *encode_newline(Encoder *e) {
|
||||
if (janet_buffer_push_bytes(e->buffer, e->newline, e->newlinelen))
|
||||
return "buffer overflow";
|
||||
/* Skip loop if no tab string */
|
||||
if (e->tablen) {
|
||||
for (int32_t i = 0; i < e->indent; i++)
|
||||
if (janet_buffer_push_bytes(e->buffer, e->tab, e->tablen))
|
||||
return "buffer overflow";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *encode_one(Encoder *e, Janet x, int depth) {
|
||||
switch(janet_type(x)) {
|
||||
default:
|
||||
goto badtype;
|
||||
case JANET_NIL:
|
||||
{
|
||||
if (janet_buffer_push_cstring(e->buffer, "null"))
|
||||
goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_FALSE:
|
||||
{
|
||||
if (janet_buffer_push_cstring(e->buffer, "false"))
|
||||
goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_TRUE:
|
||||
{
|
||||
if (janet_buffer_push_cstring(e->buffer, "true"))
|
||||
goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_INTEGER:
|
||||
{
|
||||
char cbuf[20];
|
||||
sprintf(cbuf, "%d", janet_unwrap_integer(x));
|
||||
if (janet_buffer_push_cstring(e->buffer, cbuf))
|
||||
goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_REAL:
|
||||
{
|
||||
char cbuf[25];
|
||||
sprintf(cbuf, "%.17g", janet_unwrap_real(x));
|
||||
if (janet_buffer_push_cstring(e->buffer, cbuf))
|
||||
goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_STRING:
|
||||
case JANET_SYMBOL:
|
||||
case JANET_BUFFER:
|
||||
{
|
||||
const uint8_t *bytes;
|
||||
const uint8_t *c;
|
||||
const uint8_t *end;
|
||||
int32_t len;
|
||||
janet_bytes_view(x, &bytes, &len);
|
||||
if (janet_buffer_push_u8(e->buffer, '"')) goto overflow;
|
||||
c = bytes;
|
||||
end = bytes + len;
|
||||
while (c < end) {
|
||||
|
||||
/* get codepoint */
|
||||
uint32_t codepoint;
|
||||
if (*c < 0x80) {
|
||||
/* one byte */
|
||||
codepoint = *c++;
|
||||
} else if (*c < 0xE0) {
|
||||
/* two bytes */
|
||||
if (c + 2 > end) goto overflow;
|
||||
codepoint = ((c[0] & 0x1F) << 6) |
|
||||
(c[1] & 0x3F);
|
||||
c += 2;
|
||||
} else if (*c < 0xF0) {
|
||||
/* three bytes */
|
||||
if (c + 3 > end) goto overflow;
|
||||
codepoint = ((c[0] & 0x0F) << 12) |
|
||||
((c[1] & 0x3F) << 6) |
|
||||
(c[2] & 0x3F);
|
||||
c += 3;
|
||||
} else if (*c < 0xF8) {
|
||||
/* four bytes */
|
||||
if (c + 4 > end) goto overflow;
|
||||
codepoint = ((c[0] & 0x07) << 18) |
|
||||
((c[1] & 0x3F) << 12) |
|
||||
((c[3] & 0x3F) << 6) |
|
||||
(c[3] & 0x3F);
|
||||
c += 4;
|
||||
} else {
|
||||
/* invalid */
|
||||
goto invalidutf8;
|
||||
}
|
||||
|
||||
/* write codepoint */
|
||||
if (codepoint > 0x1F && codepoint < 0x80) {
|
||||
/* Normal, no escape */
|
||||
if (codepoint == '\\' || codepoint == '"')
|
||||
if (janet_buffer_push_u8(e->buffer, '\\'))
|
||||
goto overflow;
|
||||
if (janet_buffer_push_u8(e->buffer, (uint8_t) codepoint))
|
||||
goto overflow;
|
||||
} else if (codepoint < 0x10000) {
|
||||
/* One unicode escape */
|
||||
uint8_t buf[6];
|
||||
buf[0] = '\\';
|
||||
buf[1] = 'u';
|
||||
buf[2] = (codepoint >> 12) & 0xF;
|
||||
buf[3] = (codepoint >> 8) & 0xF;
|
||||
buf[4] = (codepoint >> 4) & 0xF;
|
||||
buf[5] = codepoint & 0xF;
|
||||
if (janet_buffer_push_bytes(e->buffer, buf, sizeof(buf)))
|
||||
goto overflow;
|
||||
} else {
|
||||
/* Two unicode escapes (surrogate pair) */
|
||||
uint32_t hi, lo;
|
||||
uint8_t buf[12];
|
||||
hi = ((codepoint - 0x10000) >> 10) + 0xD800;
|
||||
lo = ((codepoint - 0x10000) & 0x3FF) + 0xDC00;
|
||||
buf[0] = '\\';
|
||||
buf[1] = 'u';
|
||||
buf[2] = (hi >> 12) & 0xF;
|
||||
buf[3] = (hi >> 8) & 0xF;
|
||||
buf[4] = (hi >> 4) & 0xF;
|
||||
buf[5] = hi & 0xF;
|
||||
buf[6] = '\\';
|
||||
buf[7] = 'u';
|
||||
buf[8] = (lo >> 12) & 0xF;
|
||||
buf[9] = (lo >> 8) & 0xF;
|
||||
buf[10] = (lo >> 4) & 0xF;
|
||||
buf[11] = lo & 0xF;
|
||||
if (janet_buffer_push_bytes(e->buffer, buf, sizeof(buf)))
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
if (janet_buffer_push_u8(e->buffer, '"')) goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_TUPLE:
|
||||
case JANET_ARRAY:
|
||||
{
|
||||
const char *err;
|
||||
const Janet *items;
|
||||
int32_t len;
|
||||
janet_indexed_view(x, &items, &len);
|
||||
if (janet_buffer_push_u8(e->buffer, '[')) goto overflow;
|
||||
e->indent++;
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
if ((err = encode_newline(e))) return err;
|
||||
if ((err = encode_one(e, items[i], depth + 1)))
|
||||
return err;
|
||||
if (janet_buffer_push_u8(e->buffer, ','))
|
||||
goto overflow;
|
||||
}
|
||||
e->indent--;
|
||||
if (e->buffer->data[e->buffer->count - 1] == ',') {
|
||||
e->buffer->count--;
|
||||
if ((err = encode_newline(e))) return err;
|
||||
}
|
||||
if (janet_buffer_push_u8(e->buffer, ']')) goto overflow;
|
||||
}
|
||||
break;
|
||||
case JANET_TABLE:
|
||||
case JANET_STRUCT:
|
||||
{
|
||||
const char *err;
|
||||
const JanetKV *kvs;
|
||||
int32_t count, capacity;
|
||||
janet_dictionary_view(x, &kvs, &count, &capacity);
|
||||
if (janet_buffer_push_u8(e->buffer, '{')) goto overflow;
|
||||
e->indent++;
|
||||
for (int32_t i = 0; i < capacity; i++) {
|
||||
if (janet_checktype(kvs[i].key, JANET_NIL))
|
||||
continue;
|
||||
if (!janet_checktype(kvs[i].key, JANET_STRING))
|
||||
return "only strings keys are allowed in objects";
|
||||
if ((err = encode_newline(e))) return err;
|
||||
if ((err = encode_one(e, kvs[i].key, depth + 1)))
|
||||
return err;
|
||||
const char *sep = e->tablen ? ": " : ":";
|
||||
if (janet_buffer_push_cstring(e->buffer, sep))
|
||||
goto overflow;
|
||||
if ((err = encode_one(e, kvs[i].value, depth + 1)))
|
||||
return err;
|
||||
if (janet_buffer_push_u8(e->buffer, ','))
|
||||
goto overflow;
|
||||
}
|
||||
e->indent--;
|
||||
if (e->buffer->data[e->buffer->count - 1] == ',') {
|
||||
e->buffer->count--;
|
||||
if ((err = encode_newline(e))) return err;
|
||||
}
|
||||
if (janet_buffer_push_u8(e->buffer, '}')) goto overflow;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
/* Errors */
|
||||
overflow:
|
||||
return "buffer overflow";
|
||||
badtype:
|
||||
return "type not supported";
|
||||
invalidutf8:
|
||||
return "string contains invalid utf-8";
|
||||
}
|
||||
|
||||
static int json_encode(JanetArgs args) {
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_MAXARITY(args, 3);
|
||||
Encoder e;
|
||||
e.indent = 0;
|
||||
e.buffer = janet_buffer(10);
|
||||
e.tab = NULL;
|
||||
e.newline = NULL;
|
||||
e.tablen = 0;
|
||||
e.newlinelen = 0;
|
||||
if (args.n >= 2) {
|
||||
JANET_ARG_BYTES(e.tab, e.tablen, args, 1);
|
||||
if (args.n >= 3) {
|
||||
JANET_ARG_BYTES(e.newline, e.newlinelen, args, 2);
|
||||
} else {
|
||||
e.newline = (const uint8_t *)"\r\n";
|
||||
e.newlinelen = 2;
|
||||
}
|
||||
}
|
||||
const char *err = encode_one(&e, args.v[0], 0);
|
||||
if (err) JANET_THROW(args, err);
|
||||
JANET_RETURN_BUFFER(args, e.buffer);
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Module Entry */
|
||||
/****************/
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"encode", json_encode,
|
||||
"(json/encode x)\n\n"
|
||||
"Encodes a janet value in JSON (utf-8)."
|
||||
},
|
||||
{"decode", json_decode,
|
||||
"(json/decode json-source)\n\n"
|
||||
"Returns a janet object after parsing JSON."
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
JANET_MODULE_ENTRY(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, "json", cfuns);
|
||||
return 0;
|
||||
}
|
||||
62
natives/sqlite3/.gitignore
vendored
62
natives/sqlite3/.gitignore
vendored
@@ -1,62 +0,0 @@
|
||||
# Created by https://www.gitignore.io/api/c
|
||||
|
||||
### C ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/c
|
||||
|
||||
sqlite3.c
|
||||
sqlite3.h
|
||||
sqlite-autoconf-3230100
|
||||
@@ -1,60 +0,0 @@
|
||||
# Copyright (c) 2018 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.
|
||||
|
||||
CFLAGS=-std=c99 -Wall -Wextra -I../../src/include -O2 -shared -fpic \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION
|
||||
TARGET=sqlite3.so
|
||||
|
||||
# MacOS specifics
|
||||
UNAME:=$(shell uname -s)
|
||||
ifeq ($(UNAME), Darwin)
|
||||
CFLAGS:=$(CFLAGS) -undefined dynamic_lookup
|
||||
endif
|
||||
|
||||
# Default target
|
||||
all: $(TARGET)
|
||||
|
||||
OBJECTS:=main.o sqlite3.o
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
sqlite-autoconf-3230100/sqlite3.%:
|
||||
curl https://www.sqlite.org/2018/sqlite-autoconf-3230100.tar.gz | tar -xvz
|
||||
|
||||
sqlite3.c: sqlite-autoconf-3230100/sqlite3.c
|
||||
cp $< $@
|
||||
sqlite3.h: sqlite-autoconf-3230100/sqlite3.h
|
||||
cp $< $@
|
||||
|
||||
%.o: %.c sqlite3.h
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm -rf sqlite-autoconf-3230100
|
||||
rm *.o
|
||||
rm sqlite3.c
|
||||
rm sqlite3.h
|
||||
rm $(TARGET)
|
||||
|
||||
install:
|
||||
cp $(TARGET) $(DST_PATH)
|
||||
|
||||
.PHONY: clean all
|
||||
@@ -1,428 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <janet/janet.h>
|
||||
|
||||
#define FLAG_CLOSED 1
|
||||
|
||||
#define MSG_DB_CLOSED "database already closed"
|
||||
|
||||
typedef struct {
|
||||
sqlite3* handle;
|
||||
int flags;
|
||||
} Db;
|
||||
|
||||
/* Close a db, noop if already closed */
|
||||
static void closedb(Db *db) {
|
||||
if (!(db->flags & FLAG_CLOSED)) {
|
||||
db->flags |= FLAG_CLOSED;
|
||||
sqlite3_close_v2(db->handle);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called to garbage collect a sqlite3 connection */
|
||||
static int gcsqlite(void *p, size_t s) {
|
||||
(void) s;
|
||||
Db *db = (Db *)p;
|
||||
closedb(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const JanetAbstractType sql_conn_type = {
|
||||
":sqlite3.connection",
|
||||
gcsqlite,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Open a new database connection */
|
||||
static int sql_open(JanetArgs args) {
|
||||
sqlite3 *conn;
|
||||
const uint8_t *filename;
|
||||
int status;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_STRING(filename, args, 0);
|
||||
status = sqlite3_open((const char *)filename, &conn);
|
||||
if (status == SQLITE_OK) {
|
||||
Db *db = (Db *) janet_abstract(&sql_conn_type, sizeof(Db));
|
||||
db->handle = conn;
|
||||
db->flags = 0;
|
||||
JANET_RETURN_ABSTRACT(args, db);
|
||||
} else {
|
||||
const char *err = sqlite3_errmsg(conn);
|
||||
JANET_THROW(args, err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close a database connection */
|
||||
static int sql_close(JanetArgs args) {
|
||||
Db *db;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_ABSTRACT(db, args, 0, &sql_conn_type);
|
||||
closedb(db);
|
||||
JANET_RETURN_NIL(args);
|
||||
}
|
||||
|
||||
/* Check for embedded NULL bytes */
|
||||
static int has_null(const uint8_t *str, int32_t len) {
|
||||
while (len--) {
|
||||
if (!str[len])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind a single parameter */
|
||||
static const char *bind1(sqlite3_stmt *stmt, int index, Janet value) {
|
||||
int res;
|
||||
switch (janet_type(value)) {
|
||||
default:
|
||||
return "invalid sql value";
|
||||
case JANET_NIL:
|
||||
res = sqlite3_bind_null(stmt, index);
|
||||
break;
|
||||
case JANET_FALSE:
|
||||
res = sqlite3_bind_int(stmt, index, 0);
|
||||
break;
|
||||
case JANET_TRUE:
|
||||
res = sqlite3_bind_int(stmt, index, 1);
|
||||
break;
|
||||
case JANET_REAL:
|
||||
res = sqlite3_bind_double(stmt, index, janet_unwrap_real(value));
|
||||
break;
|
||||
case JANET_INTEGER:
|
||||
res = sqlite3_bind_int64(stmt, index, janet_unwrap_integer(value));
|
||||
break;
|
||||
case JANET_STRING:
|
||||
case JANET_SYMBOL:
|
||||
{
|
||||
const uint8_t *str = janet_unwrap_string(value);
|
||||
int32_t len = janet_string_length(str);
|
||||
if (has_null(str, len)) {
|
||||
return "cannot have embedded nulls in text values";
|
||||
} else {
|
||||
res = sqlite3_bind_text(stmt, index, (const char *)str, len + 1, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JANET_BUFFER:
|
||||
{
|
||||
JanetBuffer *buffer = janet_unwrap_buffer(value);
|
||||
res = sqlite3_bind_blob(stmt, index, buffer->data, buffer->count, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (res != SQLITE_OK) {
|
||||
sqlite3 *db = sqlite3_db_handle(stmt);
|
||||
return sqlite3_errmsg(db);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Bind many parameters */
|
||||
static const char *bindmany(sqlite3_stmt *stmt, Janet params) {
|
||||
/* parameters */
|
||||
const Janet *seq;
|
||||
const JanetKV *kvs;
|
||||
int32_t len, cap;
|
||||
int limitindex = sqlite3_bind_parameter_count(stmt);
|
||||
if (janet_indexed_view(params, &seq, &len)) {
|
||||
if (len > limitindex + 1) {
|
||||
return "invalid index in sql parameters";
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
const char *err = bind1(stmt, i + 1, seq[i]);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else if (janet_dictionary_view(params, &kvs, &len, &cap)) {
|
||||
for (int i = 0; i < cap; i++) {
|
||||
int index = 0;
|
||||
switch (janet_type(kvs[i].key)) {
|
||||
default:
|
||||
/* Will fail */
|
||||
break;
|
||||
case JANET_NIL:
|
||||
/* Will skip as nil keys indicate empty hash table slot */
|
||||
continue;
|
||||
case JANET_INTEGER:
|
||||
index = janet_unwrap_integer(kvs[i].key);
|
||||
break;
|
||||
case JANET_STRING:
|
||||
case JANET_SYMBOL:
|
||||
{
|
||||
const uint8_t *s = janet_unwrap_string(kvs[i].key);
|
||||
index = sqlite3_bind_parameter_index(
|
||||
stmt,
|
||||
(const char *)s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (index <= 0 || index > limitindex) {
|
||||
return "invalid index in sql parameters";
|
||||
}
|
||||
const char *err = bind1(stmt, index, kvs[i].value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "invalid type for sql parameters";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Execute a statement but don't collect results */
|
||||
static const char *execute(sqlite3_stmt *stmt) {
|
||||
int status;
|
||||
const char *ret = NULL;
|
||||
do {
|
||||
status = sqlite3_step(stmt);
|
||||
} while (status == SQLITE_ROW);
|
||||
/* Check for errors */
|
||||
if (status != SQLITE_DONE) {
|
||||
sqlite3 *db = sqlite3_db_handle(stmt);
|
||||
ret = sqlite3_errmsg(db);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Execute and return values from prepared statement */
|
||||
static const char *execute_collect(sqlite3_stmt *stmt, JanetArray *rows) {
|
||||
/* Count number of columns in result */
|
||||
int ncol = sqlite3_column_count(stmt);
|
||||
int status;
|
||||
const char *ret = NULL;
|
||||
|
||||
/* Get column names */
|
||||
Janet *tupstart = janet_tuple_begin(ncol);
|
||||
for (int i = 0; i < ncol; i++) {
|
||||
tupstart[i] = janet_cstringv(sqlite3_column_name(stmt, i));
|
||||
}
|
||||
const Janet *colnames = janet_tuple_end(tupstart);
|
||||
|
||||
do {
|
||||
status = sqlite3_step(stmt);
|
||||
if (status == SQLITE_ROW) {
|
||||
JanetKV *row = janet_struct_begin(ncol);
|
||||
for (int i = 0; i < ncol; i++) {
|
||||
int t = sqlite3_column_type(stmt, i);
|
||||
Janet value;
|
||||
switch (t) {
|
||||
case SQLITE_NULL:
|
||||
value = janet_wrap_nil();
|
||||
break;
|
||||
case SQLITE_INTEGER:
|
||||
value = janet_wrap_integer(sqlite3_column_int(stmt, i));
|
||||
break;
|
||||
case SQLITE_FLOAT:
|
||||
value = janet_wrap_real(sqlite3_column_double(stmt, i));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
{
|
||||
int nbytes = sqlite3_column_bytes(stmt, i);
|
||||
uint8_t *str = janet_string_begin(nbytes);
|
||||
memcpy(str, sqlite3_column_text(stmt, i), nbytes);
|
||||
value = janet_wrap_string(janet_string_end(str));
|
||||
}
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
{
|
||||
int nbytes = sqlite3_column_bytes(stmt, i);
|
||||
JanetBuffer *b = janet_buffer(nbytes);
|
||||
memcpy(b->data, sqlite3_column_blob(stmt, i), nbytes);
|
||||
b->count = nbytes;
|
||||
value = janet_wrap_buffer(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
janet_struct_put(row, colnames[i], value);
|
||||
}
|
||||
janet_array_push(rows, janet_wrap_struct(janet_struct_end(row)));
|
||||
}
|
||||
} while (status == SQLITE_ROW);
|
||||
|
||||
/* Check for errors */
|
||||
if (status != SQLITE_DONE) {
|
||||
sqlite3 *db = sqlite3_db_handle(stmt);
|
||||
ret = sqlite3_errmsg(db);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Evaluate a string of sql */
|
||||
static int sql_eval(JanetArgs args) {
|
||||
const char *err;
|
||||
sqlite3_stmt *stmt = NULL, *stmt_next = NULL;
|
||||
const uint8_t *query;
|
||||
|
||||
JANET_MINARITY(args, 2);
|
||||
JANET_MAXARITY(args, 3);
|
||||
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||
Db *db = (Db *)janet_unwrap_abstract(args.v[0]);
|
||||
if (db->flags & FLAG_CLOSED) {
|
||||
JANET_THROW(args, MSG_DB_CLOSED);
|
||||
}
|
||||
JANET_ARG_STRING(query, args, 1);
|
||||
if (has_null(query, janet_string_length(query))) {
|
||||
err = "cannot have embedded NULL in sql statememts";
|
||||
goto error;
|
||||
}
|
||||
JanetArray *rows = janet_array(10);
|
||||
const char *c = (const char *)query;
|
||||
|
||||
/* Evaluate all statements in a loop */
|
||||
do {
|
||||
/* Compile the next statement */
|
||||
if (sqlite3_prepare_v2(db->handle, c, -1, &stmt_next, &c) != SQLITE_OK) {
|
||||
err = sqlite3_errmsg(db->handle);
|
||||
goto error;
|
||||
}
|
||||
/* Check if we have found last statement */
|
||||
if (NULL == stmt_next) {
|
||||
/* Execute current statement and collect results */
|
||||
if (stmt) {
|
||||
err = execute_collect(stmt, rows);
|
||||
if (err) goto error;
|
||||
}
|
||||
} else {
|
||||
/* Execute current statement but don't collect results. */
|
||||
if (stmt) {
|
||||
err = execute(stmt);
|
||||
if (err) goto error;
|
||||
}
|
||||
/* Bind params to next statement*/
|
||||
if (args.n == 3) {
|
||||
/* parameters */
|
||||
err = bindmany(stmt_next, args.v[2]);
|
||||
if (err) goto error;
|
||||
}
|
||||
}
|
||||
/* rotate stmt and stmt_next */
|
||||
if (stmt) sqlite3_finalize(stmt);
|
||||
stmt = stmt_next;
|
||||
stmt_next = NULL;
|
||||
} while (NULL != stmt);
|
||||
|
||||
/* Good return path */
|
||||
JANET_RETURN_ARRAY(args, rows);
|
||||
|
||||
error:
|
||||
if (stmt) sqlite3_finalize(stmt);
|
||||
if (stmt_next) sqlite3_finalize(stmt_next);
|
||||
JANET_THROW(args, err);
|
||||
}
|
||||
|
||||
/* Convert int64_t to a string */
|
||||
static const uint8_t *coerce_int64(int64_t x) {
|
||||
uint8_t bytes[40];
|
||||
int i = 0;
|
||||
/* Edge cases */
|
||||
if (x == 0) return janet_cstring("0");
|
||||
if (x == INT64_MIN) return janet_cstring("-9,223,372,036,854,775,808");
|
||||
/* Negative becomes pos */
|
||||
if (x < 0) {
|
||||
bytes[i++] = '-';
|
||||
x = -x;
|
||||
}
|
||||
while (x) {
|
||||
bytes[i++] = x % 10;
|
||||
x = x / 10;
|
||||
}
|
||||
bytes[i] = '\0';
|
||||
return janet_string(bytes, i);
|
||||
}
|
||||
|
||||
/* Gets the last inserted row id */
|
||||
static int sql_last_insert_rowid(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||
Db *db = (Db *)janet_unwrap_abstract(args.v[0]);
|
||||
if (db->flags & FLAG_CLOSED) {
|
||||
JANET_THROW(args, MSG_DB_CLOSED);
|
||||
}
|
||||
sqlite3_int64 id = sqlite3_last_insert_rowid(db->handle);
|
||||
if (id >= INT32_MIN && id <= INT32_MAX) {
|
||||
JANET_RETURN_INTEGER(args, (int32_t) id);
|
||||
}
|
||||
/* Convert to string */
|
||||
JANET_RETURN_STRING(args, coerce_int64(id));
|
||||
}
|
||||
|
||||
/* Get the sqlite3 errcode */
|
||||
static int sql_error_code(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||
Db *db = (Db *)janet_unwrap_abstract(args.v[0]);
|
||||
if (db->flags & FLAG_CLOSED) {
|
||||
JANET_THROW(args, MSG_DB_CLOSED);
|
||||
}
|
||||
int errcode = sqlite3_errcode(db->handle);
|
||||
JANET_RETURN_INTEGER(args, errcode);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"open", sql_open,
|
||||
"(sqlite3/open path)\n\n"
|
||||
"Opens a sqlite3 database on disk. Returns the database handle if the database was opened "
|
||||
"successfully, and otheriwse throws an error."
|
||||
},
|
||||
{"close", sql_close,
|
||||
"(sqlite3/close db)\n\n"
|
||||
"Closes a database. Use this to free a database after use. Returns nil."
|
||||
},
|
||||
{"eval", sql_eval,
|
||||
"(sqlite3/eval db sql [,params])\n\n"
|
||||
"Evaluate sql in the context of database db. Multiple sql statements "
|
||||
"can be changed together, and optionally parameters maybe passed in. "
|
||||
"The optional parameters maybe either an indexed data type (tuple or array), or a dictionary "
|
||||
"data type (struct or table). If params is a tuple or array, then sqlite "
|
||||
"parameters are substituted using indices. For example:\n\n"
|
||||
"\t(sqlite3/eval db `SELECT * FROM tab WHERE id = ?;` [123])\n\n"
|
||||
"Will select rows from tab where id is equal to 123. Alternatively, "
|
||||
"the programmer can use named parameters with tables or structs, like so:\n\n"
|
||||
"\t(sqlite3/eval db `SELECT * FROM tab WHERE id = :id;` {:id 123})\n\n"
|
||||
"Will return an array of rows, where each row contains a table where columns names "
|
||||
"are keys for column values."
|
||||
},
|
||||
{"last-insert-rowid", sql_last_insert_rowid,
|
||||
"(sqlite3/last-insert-rowid db)\n\n"
|
||||
"Returns the id of the last inserted row. If the id will fit into a 32-bit"
|
||||
"signed integer, will returned an integer, otherwise will return a string representation "
|
||||
"of the id (an 8 bytes string containing a long integer)."
|
||||
},
|
||||
{"error-code", sql_error_code,
|
||||
"(sqlite3/error-code db)\n\n"
|
||||
"Returns the error number of the last sqlite3 command that threw an error. Cross "
|
||||
"check these numbers with the SQLite documentation for more information."
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
JANET_MODULE_ENTRY(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, "sqlite3", cfuns);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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;
|
||||
}
|
||||
114
src/boot/boot.c
Normal file
114
src/boot/boot.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.
|
||||
*/
|
||||
|
||||
#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 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;
|
||||
|
||||
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 */
|
||||
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 = 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);
|
||||
free(boot_buffer);
|
||||
|
||||
/* Deinitialize vm */
|
||||
janet_deinit();
|
||||
|
||||
return status;
|
||||
}
|
||||
3535
src/boot/boot.janet
Normal file
3535
src/boot/boot.janet
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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;
|
||||
}
|
||||
67
src/boot/number_test.c
Normal file
67
src/boot/number_test.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.
|
||||
*/
|
||||
|
||||
#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,
|
||||
* we cannot check against bases other 10. */
|
||||
|
||||
/* Compare valid c numbers to system implementation. */
|
||||
static void test_valid_str(const char *str) {
|
||||
int err;
|
||||
double cnum, jnum;
|
||||
jnum = 0.0;
|
||||
cnum = atof(str);
|
||||
err = janet_scan_number((const uint8_t *) str, (int32_t) strlen(str), &jnum);
|
||||
assert(!err);
|
||||
assert(cnum == jnum);
|
||||
}
|
||||
|
||||
int number_test() {
|
||||
|
||||
test_valid_str("1.0");
|
||||
test_valid_str("1");
|
||||
test_valid_str("2.1");
|
||||
test_valid_str("1e10");
|
||||
test_valid_str("2e10");
|
||||
test_valid_str("1e-10");
|
||||
test_valid_str("2e-10");
|
||||
test_valid_str("1.123123e10");
|
||||
test_valid_str("1.123123e-10");
|
||||
test_valid_str("-1.23e2");
|
||||
test_valid_str("-4.5e15");
|
||||
test_valid_str("-4.5e151");
|
||||
test_valid_str("-4.5e200");
|
||||
test_valid_str("-4.5e123");
|
||||
test_valid_str("123123123123123123132123");
|
||||
test_valid_str("0000000011111111111111111111111111");
|
||||
test_valid_str(".112312333333323123123123123123123");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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 +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);
|
||||
@@ -33,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()));
|
||||
@@ -43,13 +43,33 @@ int main() {
|
||||
assert(janet_equals(janet_wrap_integer(INT32_MAX), janet_wrap_integer(INT32_MAX)));
|
||||
assert(janet_equals(janet_wrap_integer(-2), janet_wrap_integer(-2)));
|
||||
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
|
||||
assert(janet_equals(janet_wrap_real(1.4), janet_wrap_real(1.4)));
|
||||
assert(janet_equals(janet_wrap_real(3.14159265), janet_wrap_real(3.14159265)));
|
||||
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) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,14 +20,14 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include <janet.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
|
||||
JanetTable *t1, *t2;
|
||||
#include "tests.h"
|
||||
|
||||
janet_init();
|
||||
int table_test() {
|
||||
|
||||
JanetTable *t1, *t2;
|
||||
|
||||
t1 = janet_table(10);
|
||||
t2 = janet_table(0);
|
||||
@@ -39,7 +39,7 @@ int main() {
|
||||
|
||||
assert(t1->count == 4);
|
||||
assert(t1->capacity >= t1->count);
|
||||
|
||||
|
||||
assert(janet_equals(janet_table_get(t1, janet_cstringv("hello")), janet_wrap_integer(2)));
|
||||
assert(janet_equals(janet_table_get(t1, janet_cstringv("akey")), janet_wrap_integer(5)));
|
||||
assert(janet_equals(janet_table_get(t1, janet_cstringv("box")), janet_wrap_boolean(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 */
|
||||
55
src/conf/janetconf.h
Normal file
55
src/conf/janetconf.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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 15
|
||||
#define JANET_VERSION_PATCH 2
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.15.2"
|
||||
|
||||
/* #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_TYPED_ARRAY */
|
||||
/* #define JANET_NO_INT_TYPES */
|
||||
/* #define JANET_NO_EV */
|
||||
/* #define JANET_NO_REALPATH */
|
||||
/* #define JANET_NO_SYMLINKS */
|
||||
/* #define JANET_NO_UMASK */
|
||||
|
||||
/* 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_EPOLL */
|
||||
|
||||
/* 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) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,26 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#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));
|
||||
}
|
||||
|
||||
413
src/core/array.c
413
src/core/array.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,23 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#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 *) malloc(sizeof(Janet) * (size_t) capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -39,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 = 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;
|
||||
}
|
||||
|
||||
@@ -67,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;
|
||||
int64_t new_capacity = ((int64_t) capacity) * growth;
|
||||
if (new_capacity > INT32_MAX) new_capacity = INT32_MAX;
|
||||
capacity = (int32_t) new_capacity;
|
||||
newData = 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;
|
||||
}
|
||||
@@ -92,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;
|
||||
@@ -118,194 +122,271 @@ Janet janet_array_peek(JanetArray *array) {
|
||||
|
||||
/* C Functions */
|
||||
|
||||
static int cfun_new(JanetArgs args) {
|
||||
int32_t cap;
|
||||
JanetArray *array;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_INTEGER(cap, args, 0);
|
||||
array = janet_array(cap);
|
||||
JANET_RETURN_ARRAY(args, array);
|
||||
static Janet cfun_array_new(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
JanetArray *array = janet_array(cap);
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static int cfun_pop(JanetArgs args) {
|
||||
JanetArray *array;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_ARRAY(array, args, 0);
|
||||
JANET_RETURN(args, janet_array_pop(array));
|
||||
static Janet cfun_array_new_filled(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t count = janet_getinteger(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);
|
||||
}
|
||||
|
||||
static int cfun_peek(JanetArgs args) {
|
||||
JanetArray *array;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_ARRAY(array, args, 0);
|
||||
JANET_RETURN(args, janet_array_peek(array));
|
||||
static Janet cfun_array_fill(int32_t argc, Janet *argv) {
|
||||
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];
|
||||
}
|
||||
|
||||
static int cfun_push(JanetArgs args) {
|
||||
JanetArray *array;
|
||||
int32_t newcount;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_ARG_ARRAY(array, args, 0);
|
||||
newcount = array->count - 1 + args.n;
|
||||
static Janet cfun_array_pop(int32_t argc, Janet *argv) {
|
||||
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_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_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 (args.n > 1) memcpy(array->data + array->count, args.v + 1, (args.n - 1) * sizeof(Janet));
|
||||
if (argc > 1) memcpy(array->data + array->count, argv + 1, (size_t)(argc - 1) * sizeof(Janet));
|
||||
array->count = newcount;
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int cfun_ensure(JanetArgs args) {
|
||||
JanetArray *array;
|
||||
int32_t newcount;
|
||||
int32_t growth;
|
||||
JANET_FIXARITY(args, 3);
|
||||
JANET_ARG_ARRAY(array, args, 0);
|
||||
JANET_ARG_INTEGER(newcount, args, 1);
|
||||
JANET_ARG_INTEGER(growth, args, 2);
|
||||
if (newcount < 0) JANET_THROW(args, "expected positive integer");
|
||||
static Janet cfun_array_ensure(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
int32_t newcount = janet_getinteger(argv, 1);
|
||||
int32_t growth = janet_getinteger(argv, 2);
|
||||
if (newcount < 1) janet_panic("expected positive integer");
|
||||
janet_array_ensure(array, newcount, growth);
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int cfun_slice(JanetArgs args) {
|
||||
const Janet *vals;
|
||||
int32_t len;
|
||||
JanetArray *ret;
|
||||
int32_t start, end;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_MAXARITY(args, 3);
|
||||
if (!janet_indexed_view(args.v[0], &vals, &len))
|
||||
JANET_THROW(args, "expected array|tuple");
|
||||
/* Get start */
|
||||
if (args.n < 2) {
|
||||
start = 0;
|
||||
} else if (janet_checktype(args.v[1], JANET_INTEGER)) {
|
||||
start = janet_unwrap_integer(args.v[1]);
|
||||
} else {
|
||||
JANET_THROW(args, "expected integer");
|
||||
}
|
||||
/* Get end */
|
||||
if (args.n < 3) {
|
||||
end = -1;
|
||||
} else if (janet_checktype(args.v[2], JANET_INTEGER)) {
|
||||
end = janet_unwrap_integer(args.v[2]);
|
||||
} else {
|
||||
JANET_THROW(args, "expected integer");
|
||||
}
|
||||
if (start < 0) start = len + start;
|
||||
if (end < 0) end = len + end + 1;
|
||||
if (end < 0 || start < 0 || end > len || start > len)
|
||||
JANET_THROW(args, "slice range out of bounds");
|
||||
if (end >= start) {
|
||||
ret = janet_array(end - start);
|
||||
memcpy(ret->data, vals + start, sizeof(Janet) * (end - start));
|
||||
ret->count = end - start;
|
||||
} else {
|
||||
ret = janet_array(0);
|
||||
}
|
||||
JANET_RETURN_ARRAY(args, ret);
|
||||
static Janet cfun_array_slice(int32_t argc, Janet *argv) {
|
||||
JanetView view = janet_getindexed(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JanetArray *array = janet_array(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 int cfun_concat(JanetArgs args) {
|
||||
static Janet cfun_array_concat(int32_t argc, Janet *argv) {
|
||||
int32_t i;
|
||||
JanetArray *array;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_ARG_ARRAY(array, args, 0);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
switch (janet_type(args.v[i])) {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
switch (janet_type(argv[i])) {
|
||||
default:
|
||||
janet_array_push(array, args.v[i]);
|
||||
janet_array_push(array, argv[i]);
|
||||
break;
|
||||
case JANET_ARRAY:
|
||||
case JANET_TUPLE:
|
||||
{
|
||||
int32_t j, len;
|
||||
const Janet *vals;
|
||||
janet_indexed_view(args.v[i], &vals, &len);
|
||||
for (j = 0; j < len; j++)
|
||||
janet_array_push(array, vals[j]);
|
||||
}
|
||||
break;
|
||||
case JANET_TUPLE: {
|
||||
int32_t j, len = 0;
|
||||
const Janet *vals = NULL;
|
||||
janet_indexed_view(argv[i], &vals, &len);
|
||||
for (j = 0; j < len; j++)
|
||||
janet_array_push(array, vals[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
JANET_RETURN_ARRAY(args, array);
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static int cfun_insert(JanetArgs args) {
|
||||
int32_t at;
|
||||
static Janet cfun_array_insert(int32_t argc, Janet *argv) {
|
||||
size_t chunksize, restsize;
|
||||
JanetArray *array;
|
||||
JANET_MINARITY(args, 2);
|
||||
JANET_ARG_ARRAY(array, args, 0);
|
||||
JANET_ARG_INTEGER(at, args, 1);
|
||||
janet_arity(argc, 2, -1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
int32_t at = janet_getinteger(argv, 1);
|
||||
if (at < 0) {
|
||||
at = array->count + at + 1;
|
||||
at = array->count + at + 1;
|
||||
}
|
||||
if (at < 0 || at > array->count)
|
||||
JANET_THROW(args, "insertion index out of bounds");
|
||||
chunksize = (args.n - 2) * sizeof(Janet);
|
||||
janet_panicf("insertion index %d out of range [0,%d]", at, array->count);
|
||||
chunksize = (argc - 2) * sizeof(Janet);
|
||||
restsize = (array->count - at) * sizeof(Janet);
|
||||
janet_array_ensure(array, array->count + args.n - 2, 2);
|
||||
memmove(array->data + at + args.n - 2,
|
||||
array->data + at,
|
||||
restsize);
|
||||
memcpy(array->data + at, args.v + 2, chunksize);
|
||||
array->count += (args.n - 2);
|
||||
JANET_RETURN_ARRAY(args, array);
|
||||
if (INT32_MAX - (argc - 2) < array->count) {
|
||||
janet_panic("array overflow");
|
||||
}
|
||||
janet_array_ensure(array, array->count + argc - 2, 2);
|
||||
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 argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"array/new", cfun_new,
|
||||
"(array/new capacity)\n\n"
|
||||
"Creates a new empty array with a preallocated capacity. The same as "
|
||||
"(array) but can be more efficient if the maximum size of an array is known."
|
||||
static Janet cfun_array_remove(int32_t argc, Janet *argv) {
|
||||
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];
|
||||
}
|
||||
|
||||
static Janet cfun_array_trim(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
if (array->count) {
|
||||
if (array->count < array->capacity) {
|
||||
Janet *newData = 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;
|
||||
free(array->data);
|
||||
array->data = NULL;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_array_clear(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetArray *array = janet_getarray(argv, 0);
|
||||
array->count = 0;
|
||||
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_pop,
|
||||
"(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/new-filled", cfun_array_new_filled,
|
||||
JDOC("(array/new-filled count &opt value)\n\n"
|
||||
"Creates a new array of count elements, all set to value, which defaults to nil. Returns the new array.")
|
||||
},
|
||||
{"array/peek", cfun_peek,
|
||||
"(array/peek arr)\n\n"
|
||||
"Returns the last element of the array. Does not modify the array."
|
||||
{
|
||||
"array/fill", cfun_array_fill,
|
||||
JDOC("(array/fill arr &opt value)\n\n"
|
||||
"Replace all elements of an array with value (defaulting to nil) without changing the length of the array. "
|
||||
"Returns the modified array.")
|
||||
},
|
||||
{"array/push", cfun_push,
|
||||
"(array/push arr x)\n\n"
|
||||
"Insert an element in the end of an array. Modifies the input array and returns it."
|
||||
{
|
||||
"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/ensure", cfun_ensure,
|
||||
"(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/peek", cfun_array_peek,
|
||||
JDOC("(array/peek arr)\n\n"
|
||||
"Returns the last element of the array. Does not modify the array.")
|
||||
},
|
||||
{"array/slice", cfun_slice,
|
||||
"(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/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/concat", cfun_concat,
|
||||
"(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/ensure", cfun_array_ensure,
|
||||
JDOC("(array/ensure arr capacity growth)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{"array/insert", cfun_insert,
|
||||
"(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."
|
||||
{
|
||||
"array/slice", cfun_array_slice,
|
||||
JDOC("(array/slice arrtup &opt start end)\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. "
|
||||
"Note that index -1 is synonymous with index (length arrtup) to allow a full "
|
||||
"negative slice range. Returns a new array.")
|
||||
},
|
||||
{
|
||||
"array/concat", cfun_array_concat,
|
||||
JDOC("(array/concat arr & parts)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{
|
||||
"array/insert", cfun_array_insert,
|
||||
JDOC("(array/insert arr at & xs)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{
|
||||
"array/remove", cfun_array_remove,
|
||||
JDOC("(array/remove arr at &opt n)\n\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.")
|
||||
},
|
||||
{
|
||||
"array/trim", cfun_array_trim,
|
||||
JDOC("(array/trim arr)\n\n"
|
||||
"Set the backing capacity of an array to its current length. Returns the modified array.")
|
||||
},
|
||||
{
|
||||
"array/clear", cfun_array_clear,
|
||||
JDOC("(array/clear arr)\n\n"
|
||||
"Empties an array, setting it's count to 0 but does not free the backing capacity. "
|
||||
"Returns the modified array.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Load the array module */
|
||||
int janet_lib_array(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, NULL, cfuns);
|
||||
return 0;
|
||||
void janet_lib_array(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, array_cfuns);
|
||||
}
|
||||
|
||||
640
src/core/asm.c
640
src/core/asm.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,17 +20,22 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
/* Initialize a buffer */
|
||||
JanetBuffer *janet_buffer_init(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 = malloc(sizeof(uint8_t) * (size_t) capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
buffer->count = 0;
|
||||
buffer->capacity = capacity;
|
||||
@@ -54,8 +59,10 @@ 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;
|
||||
capacity *= growth;
|
||||
new_data = realloc(old, capacity * sizeof(uint8_t));
|
||||
int64_t big_capacity = ((int64_t) capacity) * growth;
|
||||
capacity = big_capacity > INT32_MAX ? INT32_MAX : (int32_t) big_capacity;
|
||||
janet_gcpressure(capacity - buffer->capacity);
|
||||
new_data = realloc(old, (size_t) capacity * sizeof(uint8_t));
|
||||
if (NULL == new_data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -77,74 +84,71 @@ void janet_buffer_setcount(JanetBuffer *buffer, int32_t count) {
|
||||
|
||||
/* Adds capacity for enough extra bytes to the buffer. Ensures that the
|
||||
* next n bytes pushed to the buffer will not cause a reallocation */
|
||||
int janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
|
||||
void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
|
||||
/* Check for buffer overflow */
|
||||
if ((int64_t)n + buffer->count > INT32_MAX) {
|
||||
return -1;
|
||||
janet_panic("buffer overflow");
|
||||
}
|
||||
int32_t new_size = buffer->count + n;
|
||||
if (new_size > buffer->capacity) {
|
||||
int32_t new_capacity = new_size * 2;
|
||||
int32_t new_capacity = (new_size > (INT32_MAX / 2)) ? INT32_MAX : (new_size * 2);
|
||||
uint8_t *new_data = realloc(buffer->data, new_capacity * sizeof(uint8_t));
|
||||
janet_gcpressure(new_capacity - buffer->capacity);
|
||||
if (NULL == new_data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
buffer->data = new_data;
|
||||
buffer->capacity = new_capacity;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push a cstring to buffer */
|
||||
int janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
|
||||
void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
|
||||
int32_t len = 0;
|
||||
while (cstring[len]) ++len;
|
||||
return janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
|
||||
janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
|
||||
}
|
||||
|
||||
/* Push multiple bytes into the buffer */
|
||||
int janet_buffer_push_bytes(JanetBuffer *buffer, const uint8_t *string, int32_t length) {
|
||||
if (janet_buffer_extra(buffer, length)) return -1;
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int janet_buffer_push_string(JanetBuffer *buffer, const uint8_t *string) {
|
||||
return janet_buffer_push_bytes(buffer, string, janet_string_length(string));
|
||||
void janet_buffer_push_string(JanetBuffer *buffer, const uint8_t *string) {
|
||||
janet_buffer_push_bytes(buffer, string, janet_string_length(string));
|
||||
}
|
||||
|
||||
/* Push a single byte to the buffer */
|
||||
int janet_buffer_push_u8(JanetBuffer *buffer, uint8_t byte) {
|
||||
if (janet_buffer_extra(buffer, 1)) return -1;
|
||||
void janet_buffer_push_u8(JanetBuffer *buffer, uint8_t byte) {
|
||||
janet_buffer_extra(buffer, 1);
|
||||
buffer->data[buffer->count] = byte;
|
||||
buffer->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push a 16 bit unsigned integer to the buffer */
|
||||
int janet_buffer_push_u16(JanetBuffer *buffer, uint16_t x) {
|
||||
if (janet_buffer_extra(buffer, 2)) return -1;
|
||||
void janet_buffer_push_u16(JanetBuffer *buffer, uint16_t x) {
|
||||
janet_buffer_extra(buffer, 2);
|
||||
buffer->data[buffer->count] = x & 0xFF;
|
||||
buffer->data[buffer->count + 1] = (x >> 8) & 0xFF;
|
||||
buffer->count += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push a 32 bit unsigned integer to the buffer */
|
||||
int janet_buffer_push_u32(JanetBuffer *buffer, uint32_t x) {
|
||||
if (janet_buffer_extra(buffer, 4)) return -1;
|
||||
void janet_buffer_push_u32(JanetBuffer *buffer, uint32_t x) {
|
||||
janet_buffer_extra(buffer, 4);
|
||||
buffer->data[buffer->count] = x & 0xFF;
|
||||
buffer->data[buffer->count + 1] = (x >> 8) & 0xFF;
|
||||
buffer->data[buffer->count + 2] = (x >> 16) & 0xFF;
|
||||
buffer->data[buffer->count + 3] = (x >> 24) & 0xFF;
|
||||
buffer->count += 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push a 64 bit unsigned integer to the buffer */
|
||||
int janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
|
||||
if (janet_buffer_extra(buffer, 8)) return -1;
|
||||
void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
|
||||
janet_buffer_extra(buffer, 8);
|
||||
buffer->data[buffer->count] = x & 0xFF;
|
||||
buffer->data[buffer->count + 1] = (x >> 8) & 0xFF;
|
||||
buffer->data[buffer->count + 2] = (x >> 16) & 0xFF;
|
||||
@@ -154,165 +158,352 @@ int janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
|
||||
buffer->data[buffer->count + 6] = (x >> 48) & 0xFF;
|
||||
buffer->data[buffer->count + 7] = (x >> 56) & 0xFF;
|
||||
buffer->count += 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* C functions */
|
||||
|
||||
static int cfun_new(JanetArgs args) {
|
||||
int32_t cap;
|
||||
JanetBuffer *buffer;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_INTEGER(cap, args, 0);
|
||||
buffer = janet_buffer(cap);
|
||||
JANET_RETURN_BUFFER(args, buffer);
|
||||
static Janet cfun_buffer_new(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
JanetBuffer *buffer = janet_buffer(cap);
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
static int cfun_u8(JanetArgs args) {
|
||||
int32_t i;
|
||||
JanetBuffer *buffer;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_ARG_BUFFER(buffer, args, 0);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
int32_t integer;
|
||||
JANET_ARG_INTEGER(integer, args, i);
|
||||
if (janet_buffer_push_u8(buffer, (uint8_t) (integer & 0xFF)))
|
||||
JANET_THROW(args, "buffer overflow");
|
||||
static Janet cfun_buffer_new_filled(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t count = janet_getinteger(argv, 0);
|
||||
int32_t byte = 0;
|
||||
if (argc == 2) {
|
||||
byte = janet_getinteger(argv, 1) & 0xFF;
|
||||
}
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
JanetBuffer *buffer = janet_buffer(count);
|
||||
if (buffer->data)
|
||||
memset(buffer->data, byte, count);
|
||||
buffer->count = count;
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
static int cfun_int(JanetArgs args) {
|
||||
int32_t i;
|
||||
JanetBuffer *buffer;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_ARG_BUFFER(buffer, args, 0);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
int32_t integer;
|
||||
JANET_ARG_INTEGER(integer, args, i);
|
||||
if (janet_buffer_push_u32(buffer, (uint32_t) integer))
|
||||
JANET_THROW(args, "buffer overflow");
|
||||
static Janet cfun_buffer_fill(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int32_t byte = 0;
|
||||
if (argc == 2) {
|
||||
byte = janet_getinteger(argv, 1) & 0xFF;
|
||||
}
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
}
|
||||
|
||||
static int cfun_chars(JanetArgs args) {
|
||||
int32_t i;
|
||||
JanetBuffer *buffer;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_ARG_BUFFER(buffer, args, 0);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
int32_t len;
|
||||
const uint8_t *str;
|
||||
JANET_ARG_BYTES(str, len, args, i);
|
||||
if (janet_buffer_push_bytes(buffer, str, len))
|
||||
JANET_THROW(args, "buffer overflow");
|
||||
if (buffer->count) {
|
||||
memset(buffer->data, byte, buffer->count);
|
||||
}
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int cfun_clear(JanetArgs args) {
|
||||
JanetBuffer *buffer;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_BUFFER(buffer, args, 0);
|
||||
static Janet cfun_buffer_trim(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
if (buffer->count < buffer->capacity) {
|
||||
int32_t newcap = buffer->count > 4 ? buffer->count : 4;
|
||||
uint8_t *newData = realloc(buffer->data, newcap);
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
buffer->data = newData;
|
||||
buffer->capacity = newcap;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_u8(int32_t argc, Janet *argv) {
|
||||
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];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
double number = janet_getnumber(argv, i);
|
||||
uint32_t word = (uint32_t) number;
|
||||
if (word != number)
|
||||
janet_panicf("cannot convert %v to machine word", argv[i]);
|
||||
janet_buffer_push_u32(buffer, word);
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_chars(int32_t argc, Janet *argv) {
|
||||
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_push(int32_t argc, Janet *argv) {
|
||||
int32_t i;
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
for (i = 1; 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);
|
||||
}
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
|
||||
static Janet cfun_buffer_clear(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
buffer->count = 0;
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int cfun_popn(JanetArgs args) {
|
||||
JanetBuffer *buffer;
|
||||
int32_t n;
|
||||
JANET_FIXARITY(args, 2);
|
||||
JANET_ARG_BUFFER(buffer, args, 0);
|
||||
JANET_ARG_INTEGER(n, args, 1);
|
||||
if (n < 0) JANET_THROW(args, "n must be non-negative");
|
||||
static Janet cfun_buffer_popn(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int32_t n = janet_getinteger(argv, 1);
|
||||
if (n < 0) janet_panic("n must be non-negative");
|
||||
if (buffer->count < n) {
|
||||
buffer->count = 0;
|
||||
} else {
|
||||
buffer->count -= n;
|
||||
}
|
||||
JANET_RETURN(args, args.v[0]);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int cfun_slice(JanetArgs args) {
|
||||
const uint8_t *data;
|
||||
int32_t len, start, end;
|
||||
JanetBuffer *ret;
|
||||
JANET_ARG_BYTES(data, len, args, 0);
|
||||
/* Get start */
|
||||
if (args.n < 2) {
|
||||
start = 0;
|
||||
} else if (janet_checktype(args.v[1], JANET_INTEGER)) {
|
||||
start = janet_unwrap_integer(args.v[1]);
|
||||
} else {
|
||||
JANET_THROW(args, "expected integer");
|
||||
}
|
||||
/* Get end */
|
||||
if (args.n < 3) {
|
||||
end = -1;
|
||||
} else if (janet_checktype(args.v[2], JANET_INTEGER)) {
|
||||
end = janet_unwrap_integer(args.v[2]);
|
||||
} else {
|
||||
JANET_THROW(args, "expected integer");
|
||||
}
|
||||
if (start < 0) start = len + start;
|
||||
if (end < 0) end = len + end + 1;
|
||||
if (end < 0 || start < 0 || end > len || start > len)
|
||||
JANET_THROW(args, "slice range out of bounds");
|
||||
if (end >= start) {
|
||||
ret = janet_buffer(end - start);
|
||||
memcpy(ret->data, data + start, end - start);
|
||||
ret->count = end - start;
|
||||
} else {
|
||||
ret = janet_buffer(0);
|
||||
}
|
||||
JANET_RETURN_BUFFER(args, ret);
|
||||
static Janet cfun_buffer_slice(int32_t argc, Janet *argv) {
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
JanetBuffer *buffer = janet_buffer(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);
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"buffer/new", cfun_new,
|
||||
"(buffer/new capacity)\n\n"
|
||||
"Creates a new, empty buffer with enough memory for capacity bytes. "
|
||||
"Returns a new buffer."
|
||||
static void bitloc(int32_t argc, Janet *argv, JanetBuffer **b, int32_t *index, int *bit) {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
double x = janet_getnumber(argv, 1);
|
||||
int64_t bitindex = (int64_t) x;
|
||||
int64_t byteindex = bitindex >> 3;
|
||||
int which_bit = bitindex & 7;
|
||||
if (bitindex != x || bitindex < 0 || byteindex >= buffer->count)
|
||||
janet_panicf("invalid bit index %v", argv[1]);
|
||||
*b = buffer;
|
||||
*index = (int32_t) byteindex;
|
||||
*bit = which_bit;
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
bitloc(argc, argv, &buffer, &index, &bit);
|
||||
buffer->data[index] |= 1 << bit;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
bitloc(argc, argv, &buffer, &index, &bit);
|
||||
buffer->data[index] &= ~(1 << bit);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
bitloc(argc, argv, &buffer, &index, &bit);
|
||||
return janet_wrap_boolean(buffer->data[index] & (1 << bit));
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) {
|
||||
int bit;
|
||||
int32_t index;
|
||||
JanetBuffer *buffer;
|
||||
bitloc(argc, argv, &buffer, &index, &bit);
|
||||
buffer->data[index] ^= (1 << bit);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
|
||||
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)
|
||||
offset_dest = janet_gethalfrange(argv, 2, dest->count, "dest-start");
|
||||
if (argc > 3)
|
||||
offset_src = janet_gethalfrange(argv, 3, src.len, "src-start");
|
||||
int32_t length_src;
|
||||
if (argc > 4) {
|
||||
int32_t src_end = janet_gethalfrange(argv, 4, src.len, "src-end");
|
||||
length_src = src_end - offset_src;
|
||||
if (length_src < 0) length_src = 0;
|
||||
} else {
|
||||
length_src = src.len - offset_src;
|
||||
}
|
||||
int64_t last = (int64_t) offset_dest + length_src;
|
||||
if (last > INT32_MAX)
|
||||
janet_panic("buffer blit out of range");
|
||||
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 Janet cfun_buffer_format(int32_t argc, Janet *argv) {
|
||||
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];
|
||||
}
|
||||
|
||||
static const JanetReg buffer_cfuns[] = {
|
||||
{
|
||||
"buffer/new", cfun_buffer_new,
|
||||
JDOC("(buffer/new capacity)\n\n"
|
||||
"Creates a new, empty buffer with enough backing memory for capacity bytes. "
|
||||
"Returns a new buffer of length 0.")
|
||||
},
|
||||
{"buffer/push-byte", cfun_u8,
|
||||
"(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/new-filled", cfun_buffer_new_filled,
|
||||
JDOC("(buffer/new-filled count &opt byte)\n\n"
|
||||
"Creates a new buffer of length count filled with byte. By default, byte is 0. "
|
||||
"Returns the new buffer.")
|
||||
},
|
||||
{"buffer/push-integer", cfun_int,
|
||||
"(buffer/push-integer buffer x)\n\n"
|
||||
"Append an integer to a buffer. The 4 bytes of the integer are appended "
|
||||
"in twos complement, big endian order. Returns the modified buffer. Will "
|
||||
"throw an error if the buffer overflows."
|
||||
{
|
||||
"buffer/fill", cfun_buffer_fill,
|
||||
JDOC("(buffer/fill buffer &opt byte)\n\n"
|
||||
"Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. "
|
||||
"Returns the modified buffer.")
|
||||
},
|
||||
{"buffer/push-string", cfun_chars,
|
||||
"(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/trim", cfun_buffer_trim,
|
||||
JDOC("(buffer/trim buffer)\n\n"
|
||||
"Set the backing capacity of the buffer to the current length of the buffer. Returns the "
|
||||
"modified buffer.")
|
||||
},
|
||||
{"buffer/popn", cfun_popn,
|
||||
"(buffer/popn buffer n)\n\n"
|
||||
"Removes the last n bytes from the buffer. Returns the modified buffer."
|
||||
{
|
||||
"buffer/push-byte", cfun_buffer_u8,
|
||||
JDOC("(buffer/push-byte buffer & xs)\n\n"
|
||||
"Append bytes to a buffer. Will expand the buffer as necessary. "
|
||||
"Returns the modified buffer. Will throw an error if the buffer overflows.")
|
||||
},
|
||||
{"buffer/clear", cfun_clear,
|
||||
"(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/push-word", cfun_buffer_word,
|
||||
JDOC("(buffer/push-word buffer & xs)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{"buffer/slice", cfun_slice,
|
||||
"(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/push-string", cfun_buffer_chars,
|
||||
JDOC("(buffer/push-string buffer & xs)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{
|
||||
"buffer/push", cfun_buffer_push,
|
||||
JDOC("(buffer/push buffer & xs)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{
|
||||
"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 &opt start end)\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 &opt dest-start src-start src-end)\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.")
|
||||
},
|
||||
{
|
||||
"buffer/format", cfun_buffer_format,
|
||||
JDOC("(buffer/format buffer format & args)\n\n"
|
||||
"Snprintf like functionality for printing values into a buffer. Returns "
|
||||
" the modified buffer.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
int janet_lib_buffer(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, NULL, cfuns);
|
||||
return 0;
|
||||
void janet_lib_buffer(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, buffer_cfuns);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,8 +20,12 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
/* Look up table for instructions */
|
||||
enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
|
||||
@@ -30,21 +34,15 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
|
||||
JINT_ST, /* JOP_TYPECHECK, */
|
||||
JINT_S, /* JOP_RETURN, */
|
||||
JINT_0, /* JOP_RETURN_NIL, */
|
||||
JINT_SSS, /* JOP_ADD_INTEGER, */
|
||||
JINT_SSI, /* JOP_ADD_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_ADD_REAL, */
|
||||
JINT_SSS, /* JOP_ADD, */
|
||||
JINT_SSS, /* JOP_SUBTRACT_INTEGER, */
|
||||
JINT_SSS, /* JOP_SUBTRACT_REAL, */
|
||||
JINT_SSS, /* JOP_SUBTRACT, */
|
||||
JINT_SSS, /* JOP_MULTIPLY_INTEGER, */
|
||||
JINT_SSI, /* JOP_MULTIPLY_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_MULTIPLY_REAL, */
|
||||
JINT_SSS, /* JOP_MULTIPLY, */
|
||||
JINT_SSS, /* JOP_DIVIDE_INTEGER, */
|
||||
JINT_SSI, /* JOP_DIVIDE_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_DIVIDE_REAL, */
|
||||
JINT_SSS, /* JOP_DIVIDE, */
|
||||
JINT_SSS, /* JOP_MODULO, */
|
||||
JINT_SSS, /* JOP_REMAINDER, */
|
||||
JINT_SSS, /* JOP_BAND, */
|
||||
JINT_SSS, /* JOP_BOR, */
|
||||
JINT_SSS, /* JOP_BXOR, */
|
||||
@@ -60,20 +58,14 @@ 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_SSS, /* JOP_GREATER_THAN_INTEGER, */
|
||||
JINT_SSI, /* JOP_GREATER_THAN_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_GREATER_THAN_REAL, */
|
||||
JINT_SSS, /* JOP_GREATER_THAN_EQUAL_REAL, */
|
||||
JINT_SSS, /* JOP_LESS_THAN, */
|
||||
JINT_SSS, /* JOP_LESS_THAN_INTEGER, */
|
||||
JINT_SSI, /* JOP_LESS_THAN_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_LESS_THAN_REAL, */
|
||||
JINT_SSS, /* JOP_LESS_THAN_EQUAL_REAL, */
|
||||
JINT_SSS, /* JOP_EQUALS, */
|
||||
JINT_SSS, /* JOP_EQUALS_INTEGER, */
|
||||
JINT_SSI, /* JOP_EQUALS_IMMEDIATE, */
|
||||
JINT_SSS, /* JOP_EQUALS_REAL, */
|
||||
JINT_SSS, /* JOP_COMPARE, */
|
||||
JINT_S, /* JOP_LOAD_NIL, */
|
||||
JINT_S, /* JOP_LOAD_TRUE, */
|
||||
@@ -92,6 +84,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, */
|
||||
@@ -99,19 +93,21 @@ 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, */
|
||||
};
|
||||
|
||||
/* 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;
|
||||
@@ -125,79 +121,69 @@ int32_t janet_verify(JanetFuncDef *def) {
|
||||
for (i = 0; i < def->bytecode_length; i++) {
|
||||
uint32_t instr = def->bytecode[i];
|
||||
/* Check for invalid instructions */
|
||||
if ((instr & 0xFF) >= JOP_INSTRUCTION_COUNT) {
|
||||
if ((instr & 0x7F) >= JOP_INSTRUCTION_COUNT) {
|
||||
return 3;
|
||||
}
|
||||
enum JanetInstructionType type = janet_instructions[instr & 0xFF];
|
||||
enum JanetInstructionType type = janet_instructions[instr & 0x7F];
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,14 +210,17 @@ 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->arity = 0;
|
||||
def->min_arity = 0;
|
||||
def->max_arity = INT32_MAX;
|
||||
def->source = NULL;
|
||||
def->sourcemap = NULL;
|
||||
def->name = NULL;
|
||||
|
||||
452
src/core/capi.c
Normal file
452
src/core/capi.c
Normal file
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#include "fiber.h"
|
||||
#endif
|
||||
|
||||
#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_jmp_buf, sig);
|
||||
#else
|
||||
longjmp(*janet_vm_jmp_buf, sig);
|
||||
#endif
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
||||
void janet_panics(const uint8_t *message) {
|
||||
janet_panicv(janet_wrap_string(message));
|
||||
}
|
||||
|
||||
void janet_panic_type(Janet x, int32_t n, int expected) {
|
||||
janet_panicf("bad slot #%d, expected %T, got %v", n, expected, x);
|
||||
}
|
||||
|
||||
void janet_panic_abstract(Janet x, int32_t n, const JanetAbstractType *at) {
|
||||
janet_panicf("bad slot #%d, expected %s, got %v", n, at->name, x);
|
||||
}
|
||||
|
||||
void janet_fixarity(int32_t arity, int32_t fix) {
|
||||
if (arity != fix)
|
||||
janet_panicf("arity mismatch, expected %d, got %d", fix, arity);
|
||||
}
|
||||
|
||||
void janet_arity(int32_t arity, int32_t min, int32_t max) {
|
||||
if (min >= 0 && arity < min)
|
||||
janet_panicf("arity mismatch, expected at least %d, got %d", min, arity);
|
||||
if (max >= 0 && arity > max)
|
||||
janet_panicf("arity mismatch, expected at most %d, got %d", max, arity);
|
||||
}
|
||||
|
||||
#define DEFINE_GETTER(name, NAME, type) \
|
||||
type janet_get##name(const Janet *argv, int32_t n) { \
|
||||
Janet x = argv[n]; \
|
||||
if (!janet_checktype(x, JANET_##NAME)) { \
|
||||
janet_panic_type(x, n, JANET_TFLAG_##NAME); \
|
||||
} \
|
||||
return janet_unwrap_##name(x); \
|
||||
}
|
||||
|
||||
#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)) {
|
||||
*out = janet_wrap_cfunction(methods->cfun);
|
||||
return 1;
|
||||
}
|
||||
methods++;
|
||||
}
|
||||
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)
|
||||
DEFINE_GETTER(array, ARRAY, JanetArray *)
|
||||
DEFINE_GETTER(tuple, TUPLE, const Janet *)
|
||||
DEFINE_GETTER(table, TABLE, JanetTable *)
|
||||
DEFINE_GETTER(struct, STRUCT, const JanetKV *)
|
||||
DEFINE_GETTER(string, STRING, const uint8_t *)
|
||||
DEFINE_GETTER(keyword, KEYWORD, const uint8_t *)
|
||||
DEFINE_GETTER(symbol, SYMBOL, const uint8_t *)
|
||||
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 *)
|
||||
|
||||
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 janet_getcstring(argv, n);
|
||||
}
|
||||
|
||||
#undef DEFINE_GETTER
|
||||
#undef DEFINE_OPT
|
||||
#undef DEFINE_OPTLEN
|
||||
|
||||
const char *janet_getcstring(const Janet *argv, int32_t n) {
|
||||
const uint8_t *jstr = janet_getstring(argv, n);
|
||||
const char *cstr = (const char *)jstr;
|
||||
if (strlen(cstr) != (size_t) janet_string_length(jstr)) {
|
||||
janet_panicf("string %v contains embedded 0s");
|
||||
}
|
||||
return cstr;
|
||||
}
|
||||
|
||||
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 32 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return janet_unwrap_integer(x);
|
||||
}
|
||||
|
||||
int64_t janet_getinteger64(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint64(x)) {
|
||||
janet_panicf("bad slot #%d, expected 64 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return (int64_t) janet_unwrap_number(x);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
Janet x = argv[n];
|
||||
JanetView view;
|
||||
if (!janet_indexed_view(x, &view.items, &view.len)) {
|
||||
janet_panic_type(x, n, JANET_TFLAG_INDEXED);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
JanetByteView janet_getbytes(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
JanetByteView view;
|
||||
if (!janet_bytes_view(x, &view.bytes, &view.len)) {
|
||||
janet_panic_type(x, n, JANET_TFLAG_BYTES);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
JanetDictView janet_getdictionary(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
JanetDictView view;
|
||||
if (!janet_dictionary_view(x, &view.kvs, &view.len, &view.cap)) {
|
||||
janet_panic_type(x, n, JANET_TFLAG_DICTIONARY);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
void *janet_getabstract(const Janet *argv, int32_t n, const JanetAbstractType *at) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checktype(x, JANET_ABSTRACT)) {
|
||||
janet_panic_abstract(x, n, at);
|
||||
}
|
||||
void *abstractx = janet_unwrap_abstract(x);
|
||||
if (janet_abstract_type(abstractx) != at) {
|
||||
janet_panic_abstract(x, n, at);
|
||||
}
|
||||
return abstractx;
|
||||
}
|
||||
|
||||
JanetRange janet_getslice(int32_t argc, const Janet *argv) {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetRange range;
|
||||
int32_t length = janet_length(argv[0]);
|
||||
if (argc == 1) {
|
||||
range.start = 0;
|
||||
range.end = length;
|
||||
} else if (argc == 2) {
|
||||
range.start = janet_checktype(argv[1], JANET_NIL)
|
||||
? 0
|
||||
: janet_gethalfrange(argv, 1, length, "start");
|
||||
range.end = length;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
274
src/core/cfuns.c
274
src/core/cfuns.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
* Copyright (c) 2020 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,19 +20,32 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#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;
|
||||
@@ -46,79 +59,189 @@ static int fixarity3(JanetFopts opts, JanetSlot *args) {
|
||||
return janet_v_count(args) == 3;
|
||||
}
|
||||
|
||||
/* Generic hanldling for $A = op $B */
|
||||
/* Generic handling for $A = op $B */
|
||||
static JanetSlot genericSS(JanetFopts opts, int op, JanetSlot s) {
|
||||
JanetSlot target = janetc_gettarget(opts);
|
||||
janetc_emit_ss(opts.compiler, op, target, s, 1);
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Generic hanldling for $A = $B op I */
|
||||
/* Generic handling for $A = $B op I */
|
||||
static JanetSlot genericSSI(JanetFopts opts, int op, JanetSlot s, int32_t imm) {
|
||||
JanetSlot target = janetc_gettarget(opts);
|
||||
janetc_emit_ssi(opts.compiler, op, target, s, imm, 1);
|
||||
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) {
|
||||
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(nullary), 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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
static JanetSlot do_next(JanetFopts opts, JanetSlot *args) {
|
||||
return opfunction(opts, args, JOP_NEXT, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_modulo(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_MODULO, 0, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_remainder(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_REMAINDER, 0, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_cmp(JanetFopts opts, JanetSlot *args) {
|
||||
return opreduce(opts, args, JOP_COMPARE, 0, janet_wrap_nil());
|
||||
}
|
||||
static JanetSlot do_put(JanetFopts opts, JanetSlot *args) {
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, args[0], args[1], args[2], 0);
|
||||
return args[0];
|
||||
if (opts.flags & JANET_FOPTS_DROP) {
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, args[0], args[1], args[2], 0);
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
} else {
|
||||
JanetSlot t = janetc_gettarget(opts);
|
||||
janetc_copy(opts.compiler, t, args[0]);
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, t, args[1], args[2], 0);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
@@ -136,37 +259,37 @@ static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) {
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Varidadic operators specialization */
|
||||
/* 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));
|
||||
}
|
||||
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_ADD_IMMEDIATE, 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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
static JanetSlot do_bnot(JanetFopts opts, JanetSlot *args) {
|
||||
return genericSS(opts, JOP_BNOT, args[0]);
|
||||
@@ -174,35 +297,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);
|
||||
@@ -211,51 +334,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},
|
||||
@@ -269,18 +374,19 @@ 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},
|
||||
{fixarity2, do_modulo},
|
||||
{fixarity2, do_remainder},
|
||||
{fixarity2, do_cmp},
|
||||
{fixarity2, do_cancel},
|
||||
};
|
||||
|
||||
const JanetFunOptimizer *janetc_funopt(uint32_t flags) {
|
||||
@@ -288,7 +394,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) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,10 +20,15 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#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) {
|
||||
JanetFopts ret;
|
||||
@@ -94,10 +99,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));
|
||||
@@ -145,6 +150,7 @@ void janetc_popscope(JanetCompiler *c) {
|
||||
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;
|
||||
@@ -163,8 +169,8 @@ void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot) {
|
||||
|
||||
/* 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;
|
||||
@@ -198,13 +204,12 @@ JanetSlot janetc_resolve(
|
||||
switch (btype) {
|
||||
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:
|
||||
{
|
||||
case JANET_BINDING_VAR: {
|
||||
JanetSlot ret = janetc_cslot(check);
|
||||
/* TODO save type info */
|
||||
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY;
|
||||
@@ -215,7 +220,7 @@ JanetSlot janetc_resolve(
|
||||
}
|
||||
|
||||
/* Symbol was found */
|
||||
found:
|
||||
found:
|
||||
|
||||
/* Constants can be returned immediately (they are stateless) */
|
||||
if (ret.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF))
|
||||
@@ -233,9 +238,14 @@ JanetSlot janetc_resolve(
|
||||
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;
|
||||
|
||||
/* Propogate env up to current scope */
|
||||
/* Propagate env up to current scope */
|
||||
int32_t envindex = -1;
|
||||
while (scope) {
|
||||
if (scope->flags & JANET_SCOPE_FUNCTION) {
|
||||
@@ -280,8 +290,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;
|
||||
@@ -308,9 +318,9 @@ JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
|
||||
JanetSlot *ret = NULL;
|
||||
JanetFopts subopts = janetc_fopts_default(c);
|
||||
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));
|
||||
@@ -318,33 +328,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 */
|
||||
@@ -401,8 +424,71 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
|
||||
/* TODO janet function inlining (no c functions)*/
|
||||
}
|
||||
if (!specialized) {
|
||||
janetc_pushslots(c, slots);
|
||||
if (opts.flags & JANET_FOPTS_TAIL) {
|
||||
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)) {
|
||||
janetc_emit_s(c, JOP_TAILCALL, fun, 0);
|
||||
retslot = janetc_cslot(janet_wrap_nil());
|
||||
retslot.flags = JANET_SLOT_RETURNED;
|
||||
@@ -429,15 +515,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) {
|
||||
@@ -445,27 +539,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_line(form) > 0) {
|
||||
if (janet_tuple_sm_line(form) >= 0) {
|
||||
c->current_mapping.line = janet_tuple_sm_line(form);
|
||||
c->current_mapping.column = janet_tuple_sm_col(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]);
|
||||
@@ -480,24 +577,38 @@ static int macroexpand1(
|
||||
!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_call(
|
||||
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 tempOut;
|
||||
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
|
||||
janet_table_put(c->env, mf_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;
|
||||
@@ -536,24 +647,25 @@ 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_sym_rvalue(opts, janet_unwrap_symbol(x));
|
||||
ret = janetc_resolve(c, janet_unwrap_symbol(x));
|
||||
break;
|
||||
case JANET_ARRAY:
|
||||
ret = janetc_array(opts, x);
|
||||
@@ -575,18 +687,43 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
|
||||
|
||||
if (c->result.status == JANET_COMPILE_ERROR)
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
c->current_mapping = last_mapping;
|
||||
if (opts.flags & JANET_FOPTS_TAIL)
|
||||
ret = janetc_return(opts.compiler, ret);
|
||||
ret = janetc_return(c, ret);
|
||||
if (opts.flags & JANET_FOPTS_HINT) {
|
||||
janetc_copy(opts.compiler, opts.hint, ret);
|
||||
janetc_copy(c, opts.hint, ret);
|
||||
ret = opts.hint;
|
||||
}
|
||||
opts.compiler->recursion_guard++;
|
||||
c->current_mapping = last_mapping;
|
||||
c->recursion_guard++;
|
||||
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();
|
||||
@@ -607,20 +744,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;
|
||||
size_t s = sizeof(int32_t) * (size_t) def->bytecode_length;
|
||||
def->bytecode = 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;
|
||||
if (NULL != c->mapbuffer && c->source) {
|
||||
size_t s = sizeof(JanetSourceMapping) * (size_t) def->bytecode_length;
|
||||
def->sourcemap = 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;
|
||||
}
|
||||
}
|
||||
@@ -629,11 +766,28 @@ 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 = 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;
|
||||
}
|
||||
|
||||
/* Pop the scope */
|
||||
janetc_popscope(c);
|
||||
|
||||
@@ -648,15 +802,15 @@ static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where)
|
||||
c->recursion_guard = JANET_RECURSION_GUARD;
|
||||
c->env = env;
|
||||
c->source = where;
|
||||
c->current_mapping.line = 0;
|
||||
c->current_mapping.column = 0;
|
||||
c->current_mapping.line = -1;
|
||||
c->current_mapping.column = -1;
|
||||
/* Init result */
|
||||
c->result.error = NULL;
|
||||
c->result.status = JANET_COMPILE_OK;
|
||||
c->result.funcdef = NULL;
|
||||
c->result.macrofiber = NULL;
|
||||
c->result.error_mapping.line = 0;
|
||||
c->result.error_mapping.column = 0;
|
||||
c->result.error_mapping.line = -1;
|
||||
c->result.error_mapping.column = -1;
|
||||
}
|
||||
|
||||
/* Deinitialize a compiler struct */
|
||||
@@ -688,6 +842,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;
|
||||
@@ -700,45 +855,48 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
|
||||
}
|
||||
|
||||
/* C Function for compiling */
|
||||
static int cfun(JanetArgs args) {
|
||||
JanetCompileResult res;
|
||||
JanetTable *t;
|
||||
JanetTable *env;
|
||||
JANET_MINARITY(args, 2);
|
||||
JANET_MAXARITY(args, 3);
|
||||
JANET_ARG_TABLE(env, args, 1);
|
||||
const uint8_t *source = NULL;
|
||||
if (args.n == 3) {
|
||||
JANET_ARG_STRING(source, args, 2);
|
||||
static Janet cfun(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetTable *env = argc > 1 ? janet_gettable(argv, 1) : janet_vm_fiber->env;
|
||||
if (NULL == env) {
|
||||
env = janet_table(0);
|
||||
janet_vm_fiber->env = env;
|
||||
}
|
||||
res = janet_compile(args.v[0], env, source);
|
||||
const uint8_t *source = NULL;
|
||||
if (argc == 3) {
|
||||
source = janet_getstring(argv, 2);
|
||||
}
|
||||
JanetCompileResult res = janet_compile(argv[0], env, source);
|
||||
if (res.status == JANET_COMPILE_OK) {
|
||||
JANET_RETURN_FUNCTION(args, janet_thunk(res.funcdef));
|
||||
return janet_wrap_function(janet_thunk(res.funcdef));
|
||||
} else {
|
||||
t = janet_table(4);
|
||||
janet_table_put(t, janet_csymbolv(":error"), janet_wrap_string(res.error));
|
||||
janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(res.error_mapping.line));
|
||||
janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(res.error_mapping.column));
|
||||
if (res.macrofiber) {
|
||||
janet_table_put(t, janet_csymbolv(":fiber"), janet_wrap_fiber(res.macrofiber));
|
||||
JanetTable *t = janet_table(4);
|
||||
janet_table_put(t, janet_ckeywordv("error"), janet_wrap_string(res.error));
|
||||
if (res.error_mapping.line > 0) {
|
||||
janet_table_put(t, janet_ckeywordv("line"), janet_wrap_integer(res.error_mapping.line));
|
||||
}
|
||||
JANET_RETURN_TABLE(args, t);
|
||||
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));
|
||||
}
|
||||
return janet_wrap_table(t);
|
||||
}
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"compile", cfun,
|
||||
"(compile ast env [, source])\n\n"
|
||||
"Compiles an Abstract Sytnax 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."
|
||||
static const JanetReg compile_cfuns[] = {
|
||||
{
|
||||
"compile", cfun,
|
||||
JDOC("(compile ast &opt env source)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
int janet_lib_compile(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, NULL, cfuns);
|
||||
return 0;
|
||||
void janet_lib_compile(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, compile_cfuns);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
* Copyright (c) 2020 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
|
||||
@@ -23,8 +23,11 @@
|
||||
#ifndef JANET_COMPILE_H
|
||||
#define JANET_COMPILE_H
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "regalloc.h"
|
||||
#endif
|
||||
|
||||
/* Tags for some functions for the prepared inliner */
|
||||
#define JANET_FUN_DEBUG 1
|
||||
@@ -32,7 +35,7 @@
|
||||
#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
|
||||
@@ -46,18 +49,19 @@
|
||||
#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
|
||||
|
||||
/* Compiler typedefs */
|
||||
typedef struct JanetCompiler JanetCompiler;
|
||||
@@ -94,6 +98,7 @@ 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 {
|
||||
@@ -124,14 +129,14 @@ struct JanetScope {
|
||||
/* Regsiter 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;
|
||||
|
||||
int32_t bytecode_start;
|
||||
int flags;
|
||||
};
|
||||
@@ -178,13 +183,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);
|
||||
};
|
||||
|
||||
/****************************************************/
|
||||
@@ -213,7 +218,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len);
|
||||
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds);
|
||||
|
||||
/* Push slots load via janetc_toslots. */
|
||||
void janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
|
||||
int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
|
||||
|
||||
/* Free slots loaded via janetc_toslots */
|
||||
void janetc_freeslots(JanetCompiler *c, JanetSlot *slots);
|
||||
@@ -240,10 +245,4 @@ JanetSlot janetc_cslot(Janet x);
|
||||
/* Search for a symbol */
|
||||
JanetSlot janetc_resolve(JanetCompiler *c, const uint8_t *sym);
|
||||
|
||||
/* Compile a symbol (or mutltisym) when used as an rvalue. */
|
||||
JanetSlot janetc_sym_rvalue(JanetFopts opts, const uint8_t *sym);
|
||||
|
||||
/* Compile an assignment to a symbol (or multisym) */
|
||||
JanetSlot janetc_sym_lvalue(JanetFopts opts, const uint8_t *sym, Janet value);
|
||||
|
||||
#endif
|
||||
|
||||
1527
src/core/core.janet
1527
src/core/core.janet
File diff suppressed because it is too large
Load Diff
1534
src/core/corelib.c
1534
src/core/corelib.c
File diff suppressed because it is too large
Load Diff
409
src/core/debug.c
Normal file
409
src/core/debug.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "gc.h"
|
||||
#include "state.h"
|
||||
#include "util.h"
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
/* Implements functionality to build a debugger from within janet.
|
||||
* The repl should also be able to serve as pretty featured debugger
|
||||
* out of the box. */
|
||||
|
||||
/* Add a break point to a function */
|
||||
void janet_debug_break(JanetFuncDef *def, int32_t pc) {
|
||||
if (pc >= def->bytecode_length || pc < 0)
|
||||
janet_panic("invalid bytecode offset");
|
||||
def->bytecode[pc] |= 0x80;
|
||||
}
|
||||
|
||||
/* Remove a break point from a function */
|
||||
void janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
|
||||
if (pc >= def->bytecode_length || pc < 0)
|
||||
janet_panic("invalid bytecode offset");
|
||||
def->bytecode[pc] &= ~((uint32_t)0x80);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a location for a breakpoint given a source file an
|
||||
* location.
|
||||
*/
|
||||
void janet_debug_find(
|
||||
JanetFuncDef **def_out, int32_t *pc_out,
|
||||
const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) {
|
||||
/* Scan the heap for right func def */
|
||||
JanetGCObject *current = janet_vm_blocks;
|
||||
/* Keep track of the best source mapping we have seen so far */
|
||||
int32_t besti = -1;
|
||||
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);
|
||||
if (def->sourcemap &&
|
||||
def->source &&
|
||||
!janet_string_compare(source, def->source)) {
|
||||
/* Correct source file, check mappings. The chosen
|
||||
* 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 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;
|
||||
}
|
||||
if (best_def) {
|
||||
*def_out = best_def;
|
||||
*pc_out = besti;
|
||||
} else {
|
||||
janet_panic("could not find breakpoint");
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
int32_t fi;
|
||||
const char *errstr = (const char *)janet_to_string(err);
|
||||
JanetFiber **fibers = NULL;
|
||||
|
||||
/* Don't print error line if it is nil. */
|
||||
int wrote_error = janet_checktype(err, JANET_NIL);
|
||||
|
||||
int print_color = janet_truthy(janet_dyn("err-color"));
|
||||
if (print_color) janet_eprintf("\x1b[31m");
|
||||
|
||||
while (fiber) {
|
||||
janet_v_push(fibers, fiber);
|
||||
fiber = fiber->child;
|
||||
}
|
||||
|
||||
for (fi = janet_v_count(fibers) - 1; fi >= 0; fi--) {
|
||||
fiber = fibers[fi];
|
||||
int32_t i = fiber->frame;
|
||||
while (i > 0) {
|
||||
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
JanetFuncDef *def = NULL;
|
||||
i = frame->prevframe;
|
||||
|
||||
/* Print prelude to stack frame */
|
||||
if (!wrote_error) {
|
||||
JanetFiberStatus status = janet_fiber_status(fiber);
|
||||
const char *prefix = status == JANET_STATUS_ERROR ? "" : "status ";
|
||||
janet_eprintf("%s%s: %s\n",
|
||||
prefix,
|
||||
janet_status_names[status],
|
||||
errstr);
|
||||
wrote_error = 1;
|
||||
}
|
||||
|
||||
janet_eprintf(" in");
|
||||
|
||||
if (frame->func) {
|
||||
def = frame->func->def;
|
||||
janet_eprintf(" %s", def->name ? (const char *)def->name : "<anonymous>");
|
||||
if (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))
|
||||
janet_eprintf(" %s", (const char *)janet_to_string(name));
|
||||
else
|
||||
janet_eprintf(" <cfunction>");
|
||||
}
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL)
|
||||
janet_eprintf(" (tailcall)");
|
||||
if (frame->func && frame->pc) {
|
||||
int32_t off = (int32_t)(frame->pc - def->bytecode);
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
janet_eprintf(" on line %d, column %d", mapping.line, mapping.column);
|
||||
} else {
|
||||
janet_eprintf(" pc=%d", off);
|
||||
}
|
||||
}
|
||||
janet_eprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (print_color) janet_eprintf("\x1b[0m");
|
||||
|
||||
janet_v_free(fibers);
|
||||
}
|
||||
|
||||
/*
|
||||
* CFuns
|
||||
*/
|
||||
|
||||
/* 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, 3);
|
||||
const uint8_t *source = janet_getstring(argv, 0);
|
||||
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.
|
||||
* Takes a function and byte offset*/
|
||||
static void helper_find_fun(int32_t argc, Janet *argv, JanetFuncDef **def, int32_t *bytecode_offset) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetFunction *func = janet_getfunction(argv, 0);
|
||||
int32_t offset = (argc == 2) ? janet_getinteger(argv, 1) : 0;
|
||||
*def = func->def;
|
||||
*bytecode_offset = offset;
|
||||
}
|
||||
|
||||
static Janet cfun_debug_break(int32_t argc, Janet *argv) {
|
||||
JanetFuncDef *def;
|
||||
int32_t offset;
|
||||
helper_find(argc, argv, &def, &offset);
|
||||
janet_debug_break(def, offset);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) {
|
||||
JanetFuncDef *def;
|
||||
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) {
|
||||
JanetFuncDef *def;
|
||||
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) {
|
||||
JanetFuncDef *def;
|
||||
int32_t offset;
|
||||
helper_find_fun(argc, argv, &def, &offset);
|
||||
janet_debug_unbreak(def, offset);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_debug_lineage(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
JanetArray *array = janet_array(0);
|
||||
while (fiber) {
|
||||
janet_array_push(array, janet_wrap_fiber(fiber));
|
||||
fiber = fiber->child;
|
||||
}
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
/* Extract info from one stack frame */
|
||||
static Janet doframe(JanetStackFrame *frame) {
|
||||
int32_t off;
|
||||
JanetTable *t = janet_table(3);
|
||||
JanetFuncDef *def = NULL;
|
||||
if (frame->func) {
|
||||
janet_table_put(t, janet_ckeywordv("function"), janet_wrap_function(frame->func));
|
||||
def = frame->func->def;
|
||||
if (def->name) {
|
||||
janet_table_put(t, janet_ckeywordv("name"), janet_wrap_string(def->name));
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
janet_table_put(t, janet_ckeywordv("c"), janet_wrap_true());
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL) {
|
||||
janet_table_put(t, janet_ckeywordv("tail"), janet_wrap_true());
|
||||
}
|
||||
if (frame->func && frame->pc) {
|
||||
Janet *stack = (Janet *)frame + JANET_FRAME_SIZE;
|
||||
JanetArray *slots;
|
||||
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-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);
|
||||
safe_memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
|
||||
slots->count = def->slotcount;
|
||||
janet_table_put(t, janet_ckeywordv("slots"), janet_wrap_array(slots));
|
||||
}
|
||||
return janet_wrap_table(t);
|
||||
}
|
||||
|
||||
static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
JanetArray *array = janet_array(0);
|
||||
{
|
||||
int32_t i = fiber->frame;
|
||||
JanetStackFrame *frame;
|
||||
while (i > 0) {
|
||||
frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
janet_array_push(array, doframe(frame));
|
||||
i = frame->prevframe;
|
||||
}
|
||||
}
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
|
||||
janet_stacktrace(fiber, x);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
JanetArray *array = janet_array(fiber->stacktop - fiber->stackstart);
|
||||
memcpy(array->data, fiber->data + fiber->stackstart, array->capacity * sizeof(Janet));
|
||||
array->count = array->capacity;
|
||||
return janet_wrap_array(array);
|
||||
}
|
||||
|
||||
static Janet cfun_debug_step(int32_t argc, Janet *argv) {
|
||||
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;
|
||||
}
|
||||
|
||||
static const JanetReg debug_cfuns[] = {
|
||||
{
|
||||
"debug/break", cfun_debug_break,
|
||||
JDOC("(debug/break source line col)\n\n"
|
||||
"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"
|
||||
"wil set a breakpoint at line 10, 4th column of the file core.janet.")
|
||||
},
|
||||
{
|
||||
"debug/unbreak", cfun_debug_unbreak,
|
||||
JDOC("(debug/unbreak source line column)\n\n"
|
||||
"Remove a breakpoint with a source key at a given line and column. "
|
||||
"Will throw an error if the breakpoint "
|
||||
"cannot be found.")
|
||||
},
|
||||
{
|
||||
"debug/fbreak", cfun_debug_fbreak,
|
||||
JDOC("(debug/fbreak fun &opt pc)\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 &opt pc)\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"
|
||||
"* :c - true if the stack frame is a c function invocation\n\n"
|
||||
"* :column - the current source column of the stack frame\n\n"
|
||||
"* :function - the function that the stack frame represents\n\n"
|
||||
"* :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")
|
||||
},
|
||||
{
|
||||
"debug/stacktrace", cfun_debug_stacktrace,
|
||||
JDOC("(debug/stacktrace fiber &opt err)\n\n"
|
||||
"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, will skipp the error line. 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.")
|
||||
},
|
||||
{
|
||||
"debug/step", cfun_debug_step,
|
||||
JDOC("(debug/step fiber &opt x)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_debug(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, debug_cfuns);
|
||||
}
|
||||
120
src/core/emit.c
120
src/core/emit.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,10 +20,13 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "emit.h"
|
||||
#include "vector.h"
|
||||
#include "regalloc.h"
|
||||
#endif
|
||||
|
||||
/* Get a register */
|
||||
int32_t janetc_allocfar(JanetCompiler *c) {
|
||||
@@ -34,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);
|
||||
}
|
||||
@@ -61,7 +64,7 @@ static int32_t janetc_const(JanetCompiler *c, Janet x) {
|
||||
if (janet_equals(x, scope->consts[i]))
|
||||
return i;
|
||||
}
|
||||
/* Ensure not too many constsants. */
|
||||
/* Ensure not too many constants. */
|
||||
if (len >= 0xFFFF) {
|
||||
janetc_cerror(c, "too many constants");
|
||||
return 0;
|
||||
@@ -76,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_INTEGER:
|
||||
{
|
||||
int32_t i = janet_unwrap_integer(k);
|
||||
if (i <= INT16_MAX && i >= INT16_MIN) {
|
||||
janetc_emit(c,
|
||||
(i << 16) |
|
||||
(reg << 8) |
|
||||
JOP_LOAD_INTEGER);
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -109,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);
|
||||
}
|
||||
}
|
||||
@@ -203,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) {
|
||||
@@ -219,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;
|
||||
@@ -238,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);
|
||||
@@ -292,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);
|
||||
@@ -325,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) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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
|
||||
@@ -23,7 +23,9 @@
|
||||
#ifndef JANET_EMIT_H
|
||||
#define JANET_EMIT_H
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include "compile.h"
|
||||
#endif
|
||||
|
||||
void janetc_emit(JanetCompiler *c, uint32_t instr);
|
||||
|
||||
@@ -40,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);
|
||||
|
||||
|
||||
2333
src/core/ev.c
Normal file
2333
src/core/ev.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,38 +20,36 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include "line.h"
|
||||
/* Feature test macros */
|
||||
|
||||
extern const unsigned char *janet_gen_init;
|
||||
extern int32_t janet_gen_init_size;
|
||||
#ifndef JANET_FEATURES_H_defined
|
||||
#define JANET_FEATURES_H_defined
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i, status;
|
||||
JanetArray *args;
|
||||
JanetTable *env;
|
||||
#if defined(__NetBSD__) || defined(__APPLE__) || defined(__OpenBSD__) \
|
||||
|| defined(__bsdi__) || defined(__DragonFly__)
|
||||
/* Use BSD source on any BSD systems, include OSX */
|
||||
# define _BSD_SOURCE
|
||||
#else
|
||||
/* Use POSIX feature flags */
|
||||
# ifndef _POSIX_C_SOURCE
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Set up VM */
|
||||
janet_init();
|
||||
env = janet_core_env();
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Create args tuple */
|
||||
args = janet_array(argc);
|
||||
for (i = 0; i < argc; i++)
|
||||
janet_array_push(args, janet_cstringv(argv[i]));
|
||||
janet_def(env, "process/args", janet_wrap_array(args), "Command line arguments.");
|
||||
/* Needed for realpath on linux */
|
||||
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
|
||||
#define _XOPEN_SOURCE 500
|
||||
#endif
|
||||
|
||||
/* Expose line getter */
|
||||
janet_def(env, "getline", janet_wrap_cfunction(janet_line_getter), NULL);
|
||||
janet_register("getline", janet_line_getter);
|
||||
janet_line_init();
|
||||
/* 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
|
||||
|
||||
/* Run startup script */
|
||||
status = janet_dobytes(env, janet_gen_init, janet_gen_init_size, "init.janet", NULL);
|
||||
|
||||
/* Deinitialize vm */
|
||||
janet_deinit();
|
||||
janet_line_deinit();
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
669
src/core/fiber.c
669
src/core/fiber.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2021 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,79 +20,131 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "fiber.h"
|
||||
#include "state.h"
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
static JanetFiber *make_fiber(int32_t capacity) {
|
||||
Janet *data;
|
||||
JanetFiber *fiber = janet_gcalloc(JANET_MEMORY_FIBER, sizeof(JanetFiber));
|
||||
if (capacity < 16) {
|
||||
capacity = 16;
|
||||
}
|
||||
fiber->capacity = capacity;
|
||||
data = malloc(sizeof(Janet) * capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
fiber->data = data;
|
||||
static void fiber_reset(JanetFiber *fiber) {
|
||||
fiber->maxstack = JANET_STACK_MAX;
|
||||
fiber->frame = 0;
|
||||
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);
|
||||
return fiber;
|
||||
}
|
||||
|
||||
/* Initialize a new fiber */
|
||||
JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity) {
|
||||
JanetFiber *fiber = make_fiber(capacity);
|
||||
if (janet_fiber_funcframe(fiber, callee))
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_ERROR);
|
||||
return fiber;
|
||||
}
|
||||
|
||||
/* Clear a fiber (reset it) with argn values on the stack. */
|
||||
JanetFiber *janet_fiber_n(JanetFunction *callee, int32_t capacity, const Janet *argv, int32_t argn) {
|
||||
int32_t newstacktop;
|
||||
JanetFiber *fiber = make_fiber(capacity);
|
||||
newstacktop = fiber->stacktop + argn;
|
||||
if (newstacktop >= fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * newstacktop);
|
||||
static JanetFiber *fiber_alloc(int32_t capacity) {
|
||||
Janet *data;
|
||||
JanetFiber *fiber = janet_gcalloc(JANET_MEMORY_FIBER, sizeof(JanetFiber));
|
||||
if (capacity < 32) {
|
||||
capacity = 32;
|
||||
}
|
||||
memcpy(fiber->data + fiber->stacktop, argv, argn * sizeof(Janet));
|
||||
fiber->stacktop = newstacktop;
|
||||
if (janet_fiber_funcframe(fiber, callee))
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_ERROR);
|
||||
fiber->capacity = capacity;
|
||||
data = 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;
|
||||
}
|
||||
|
||||
/* Create a new fiber with argn values on the stack by reusing a fiber. */
|
||||
JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee, int32_t argc, const Janet *argv) {
|
||||
int32_t newstacktop;
|
||||
fiber_reset(fiber);
|
||||
if (argc) {
|
||||
newstacktop = fiber->stacktop + argc;
|
||||
if (newstacktop >= fiber->capacity) {
|
||||
janet_fiber_setcapacity(fiber, 2 * newstacktop);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* Create a new fiber with argn values on the stack. */
|
||||
JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, const Janet *argv) {
|
||||
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 = malloc(sizeof(Janet) * n);
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(newData, fiber->data, fiber->capacity * sizeof(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) {
|
||||
int32_t old_size = fiber->capacity;
|
||||
int32_t diff = n - old_size;
|
||||
Janet *newData = 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;
|
||||
@@ -101,9 +153,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;
|
||||
@@ -113,14 +166,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;
|
||||
@@ -132,8 +196,16 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
int32_t nextstacktop = nextframe + func->def->slotcount + JANET_FRAME_SIZE;
|
||||
int32_t next_arity = fiber->stacktop - fiber->stackstart;
|
||||
|
||||
/* Check strict arity before messing with state */
|
||||
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) */
|
||||
@@ -154,19 +226,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));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check strict arity AFTER getting fiber to valid state. */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
||||
if (func->def->arity != next_arity) {
|
||||
return 1;
|
||||
fiber->data[tuplehead] = st
|
||||
? make_struct_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead)
|
||||
: janet_wrap_tuple(janet_tuple_n(
|
||||
fiber->data + tuplehead,
|
||||
oldtop - tuplehead));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,17 +251,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_env_valid(env);
|
||||
int32_t len = env->length;
|
||||
size_t s = sizeof(Janet) * (size_t) len;
|
||||
Janet *vmem = 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;
|
||||
@@ -198,14 +332,22 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
int32_t next_arity = fiber->stacktop - fiber->stackstart;
|
||||
int32_t stacksize;
|
||||
|
||||
/* Check strict arity before messing with state */
|
||||
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;
|
||||
Janet *args = fiber->data + fiber->stackstart;
|
||||
|
||||
/* Detatch old function */
|
||||
/* Detach old function */
|
||||
if (NULL != janet_fiber_frame(fiber)->func)
|
||||
janet_env_detach(janet_fiber_frame(fiber)->env);
|
||||
janet_fiber_frame(fiber)->env = NULL;
|
||||
@@ -213,14 +355,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 {
|
||||
@@ -241,13 +390,6 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
janet_fiber_frame(fiber)->pc = func->def->bytecode;
|
||||
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_TAILCALL;
|
||||
|
||||
/* Check strict arity AFTER getting fiber to valid state. */
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
||||
if (func->def->arity != next_arity) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Good return */
|
||||
return 0;
|
||||
}
|
||||
@@ -262,6 +404,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 */
|
||||
@@ -277,8 +423,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;
|
||||
@@ -292,34 +437,59 @@ 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 int cfun_new(JanetArgs args) {
|
||||
JanetFiber *fiber;
|
||||
JanetFunction *func;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_MAXARITY(args, 2);
|
||||
JANET_ARG_FUNCTION(func, args, 0);
|
||||
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
||||
if (func->def->arity != 0) {
|
||||
JANET_THROW(args, "expected nullary function in fiber constructor");
|
||||
}
|
||||
static Janet cfun_fiber_getenv(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return fiber->env ?
|
||||
janet_wrap_table(fiber->env) :
|
||||
janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_setenv(int32_t argc, Janet *argv) {
|
||||
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);
|
||||
}
|
||||
fiber = janet_fiber(func, 64);
|
||||
if (args.n == 2) {
|
||||
const uint8_t *flags;
|
||||
int32_t len, i;
|
||||
JANET_ARG_BYTES(flags, len, args, 1);
|
||||
fiber->flags = 0;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetFunction *func = janet_getfunction(argv, 0);
|
||||
JanetFiber *fiber;
|
||||
if (func->def->min_arity > 1) {
|
||||
janet_panicf("fiber function must accept 0 or 1 arguments");
|
||||
}
|
||||
fiber = janet_fiber(func, 64, func->def->min_arity, NULL);
|
||||
if (argc == 2) {
|
||||
int32_t i;
|
||||
JanetByteView view = janet_getbytes(argv, 1);
|
||||
fiber->flags = JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (flags[i] >= '0' && flags[i] <= '9') {
|
||||
fiber->flags |= JANET_FIBER_MASK_USERN(flags[i] - '0');
|
||||
for (i = 0; i < view.len; i++) {
|
||||
if (view.bytes[i] >= '0' && view.bytes[i] <= '9') {
|
||||
fiber->flags |= JANET_FIBER_MASK_USERN(view.bytes[i] - '0');
|
||||
} else {
|
||||
switch (flags[i]) {
|
||||
switch (view.bytes[i]) {
|
||||
default:
|
||||
JANET_THROW(args, "invalid flag, expected a, d, e, u, or y");
|
||||
case ':':
|
||||
janet_panicf("invalid flag %c, expected a, t, d, e, u, y, i, or p", view.bytes[i]);
|
||||
break;
|
||||
case 'a':
|
||||
fiber->flags |=
|
||||
@@ -328,6 +498,15 @@ static int cfun_new(JanetArgs args) {
|
||||
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;
|
||||
@@ -340,209 +519,171 @@ static int cfun_new(JanetArgs args) {
|
||||
case 'y':
|
||||
fiber->flags |= JANET_FIBER_MASK_YIELD;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
JANET_RETURN_FIBER(args, fiber);
|
||||
return janet_wrap_fiber(fiber);
|
||||
}
|
||||
|
||||
static int cfun_status(JanetArgs args) {
|
||||
JanetFiber *fiber;
|
||||
const char *status = "";
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_FIBER(fiber, args, 0);
|
||||
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
|
||||
JANET_FIBER_STATUS_OFFSET;
|
||||
switch (s) {
|
||||
case JANET_STATUS_DEAD: status = ":dead"; break;
|
||||
case JANET_STATUS_ERROR: status = ":error"; break;
|
||||
case JANET_STATUS_DEBUG: status = ":debug"; break;
|
||||
case JANET_STATUS_PENDING: status = ":pending"; break;
|
||||
case JANET_STATUS_USER0: status = ":user0"; break;
|
||||
case JANET_STATUS_USER1: status = ":user1"; break;
|
||||
case JANET_STATUS_USER2: status = ":user2"; break;
|
||||
case JANET_STATUS_USER3: status = ":user3"; break;
|
||||
case JANET_STATUS_USER4: status = ":user4"; break;
|
||||
case JANET_STATUS_USER5: status = ":user5"; break;
|
||||
case JANET_STATUS_USER6: status = ":user6"; break;
|
||||
case JANET_STATUS_USER7: status = ":user7"; break;
|
||||
case JANET_STATUS_USER8: status = ":user8"; break;
|
||||
case JANET_STATUS_USER9: status = ":user9"; break;
|
||||
case JANET_STATUS_NEW: status = ":new"; break;
|
||||
default:
|
||||
case JANET_STATUS_ALIVE: status = ":alive"; break;
|
||||
}
|
||||
JANET_RETURN_CSYMBOL(args, status);
|
||||
static Janet cfun_fiber_status(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
uint32_t s = janet_fiber_status(fiber);
|
||||
return janet_ckeywordv(janet_status_names[s]);
|
||||
}
|
||||
|
||||
/* Extract info from one stack frame */
|
||||
static Janet doframe(JanetStackFrame *frame) {
|
||||
int32_t off;
|
||||
JanetTable *t = janet_table(3);
|
||||
JanetFuncDef *def = NULL;
|
||||
if (frame->func) {
|
||||
janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
|
||||
def = frame->func->def;
|
||||
if (def->name) {
|
||||
janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
|
||||
}
|
||||
} 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_csymbolv(":name"), name);
|
||||
}
|
||||
}
|
||||
janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL) {
|
||||
janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
|
||||
}
|
||||
if (frame->func && frame->pc) {
|
||||
off = (int32_t) (frame->pc - def->bytecode);
|
||||
janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(mapping.line));
|
||||
janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(mapping.column));
|
||||
}
|
||||
if (def->source) {
|
||||
janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
|
||||
}
|
||||
}
|
||||
return janet_wrap_table(t);
|
||||
static Janet cfun_fiber_current(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_fiber(janet_vm_fiber);
|
||||
}
|
||||
|
||||
static int cfun_stack(JanetArgs args) {
|
||||
JanetFiber *fiber;
|
||||
JanetArray *array;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_FIBER(fiber, args, 0);
|
||||
array = janet_array(0);
|
||||
{
|
||||
int32_t i = fiber->frame;
|
||||
JanetStackFrame *frame;
|
||||
while (i > 0) {
|
||||
frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||
janet_array_push(array, doframe(frame));
|
||||
i = frame->prevframe;
|
||||
}
|
||||
}
|
||||
JANET_RETURN_ARRAY(args, array);
|
||||
static Janet cfun_fiber_root(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_fiber(janet_vm_root_fiber);
|
||||
}
|
||||
|
||||
static int cfun_current(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 0);
|
||||
JANET_RETURN_FIBER(args, janet_vm_fiber);
|
||||
static Janet cfun_fiber_maxstack(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return janet_wrap_integer(fiber->maxstack);
|
||||
}
|
||||
|
||||
static int cfun_lineage(JanetArgs args) {
|
||||
JanetFiber *fiber;
|
||||
JanetArray *array;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_FIBER(fiber, args, 0);
|
||||
array = janet_array(0);
|
||||
while (fiber) {
|
||||
janet_array_push(array, janet_wrap_fiber(fiber));
|
||||
fiber = fiber->child;
|
||||
}
|
||||
JANET_RETURN_ARRAY(args, array);
|
||||
}
|
||||
|
||||
static int cfun_maxstack(JanetArgs args) {
|
||||
JanetFiber *fiber;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_FIBER(fiber, args, 0);
|
||||
JANET_RETURN_INTEGER(args, fiber->maxstack);
|
||||
}
|
||||
|
||||
static int cfun_setmaxstack(JanetArgs args) {
|
||||
JanetFiber *fiber;
|
||||
int32_t maxs;
|
||||
JANET_FIXARITY(args, 2);
|
||||
JANET_ARG_FIBER(fiber, args, 0);
|
||||
JANET_ARG_INTEGER(maxs, args, 1);
|
||||
static Janet cfun_fiber_setmaxstack(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
int32_t maxs = janet_getinteger(argv, 1);
|
||||
if (maxs < 0) {
|
||||
JANET_THROW(args, "expected positive integer");
|
||||
janet_panic("expected positive integer");
|
||||
}
|
||||
fiber->maxstack = maxs;
|
||||
JANET_RETURN_FIBER(args, fiber);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"fiber/new", cfun_new,
|
||||
"(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 symbol 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"
|
||||
static Janet cfun_fiber_can_resume(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
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 janet_wrap_boolean(!isFinished);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_last_value(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
return fiber->last_value;
|
||||
}
|
||||
|
||||
static const JanetReg fiber_cfuns[] = {
|
||||
{
|
||||
"fiber/new", cfun_fiber_new,
|
||||
JDOC("(fiber/new func &opt 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. 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"
|
||||
"* :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")
|
||||
},
|
||||
{"fiber/status", cfun_status,
|
||||
"(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/status", cfun_fiber_status,
|
||||
JDOC("(fiber/status fib)\n\n"
|
||||
"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-9) - the fiber is suspended by a user signal\n"
|
||||
"* :alive - the fiber is currently running and cannot be resumed\n"
|
||||
"* :new - the fiber has just been created and not yet run")
|
||||
},
|
||||
{"fiber/stack", cfun_stack,
|
||||
"(fiber/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 invokation\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 filename or other identifier for the source code\n"
|
||||
"\t:tail - boolean indicating a tail call"
|
||||
{
|
||||
"fiber/root", cfun_fiber_root,
|
||||
JDOC("(fiber/root)\n\n"
|
||||
"Returns the current root fiber. The root fiber is the oldest ancestor "
|
||||
"that does not have a parent.")
|
||||
},
|
||||
{"fiber/current", cfun_current,
|
||||
"(fiber/current)\n\n"
|
||||
"Returns the currently running fiber."
|
||||
{
|
||||
"fiber/current", cfun_fiber_current,
|
||||
JDOC("(fiber/current)\n\n"
|
||||
"Returns the currently running fiber.")
|
||||
},
|
||||
{"fiber/lineage", cfun_lineage,
|
||||
"(fiber/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."
|
||||
{
|
||||
"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/maxstack", cfun_maxstack,
|
||||
"(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 stackoverflow 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.")
|
||||
},
|
||||
{"fiber/setmaxstack", cfun_setmaxstack,
|
||||
"(fiber/setmaxstack fib maxstack)\n\n"
|
||||
"Sets the maximum stack size in janet values for a fiber. By default, the "
|
||||
"maximum stacksize is usually 8192."
|
||||
{
|
||||
"fiber/getenv", cfun_fiber_getenv,
|
||||
JDOC("(fiber/getenv fiber)\n\n"
|
||||
"Gets the environment for a fiber. Returns nil if no such table is "
|
||||
"set yet.")
|
||||
},
|
||||
{
|
||||
"fiber/setenv", cfun_fiber_setenv,
|
||||
JDOC("(fiber/setenv fiber table)\n\n"
|
||||
"Sets the environment table for a fiber. Set to nil to remove the current "
|
||||
"environment.")
|
||||
},
|
||||
{
|
||||
"fiber/can-resume?", cfun_fiber_can_resume,
|
||||
JDOC("(fiber/can-resume? fiber)\n\n"
|
||||
"Check if a fiber is finished and cannot be resumed.")
|
||||
},
|
||||
{
|
||||
"fiber/last-value", cfun_fiber_last_value,
|
||||
JDOC("(fiber/last-value\n\n"
|
||||
"Get the last value returned or signaled from the fiber.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
int janet_lib_fiber(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, NULL, cfuns);
|
||||
return 0;
|
||||
void janet_lib_fiber(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, fiber_cfuns);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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
|
||||
@@ -23,7 +23,39 @@
|
||||
#ifndef JANET_FIBER_H_defined
|
||||
#define JANET_FIBER_H_defined
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include <janet.h>
|
||||
#endif
|
||||
|
||||
/* 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_FLAG_SCHEDULED 0x800000
|
||||
#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
|
||||
|
||||
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
|
||||
|
||||
@@ -43,5 +75,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
|
||||
|
||||
349
src/core/gc.c
349
src/core/gc.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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,38 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#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
|
||||
|
||||
struct JanetScratch {
|
||||
JanetScratchFinalizer finalize;
|
||||
long long mem[]; /* for proper alignment */
|
||||
};
|
||||
|
||||
/* 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 size_t janet_vm_gc_interval;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_next_collection;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_block_count;
|
||||
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;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_root_count;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_root_capacity;
|
||||
|
||||
/* Scratch Memory */
|
||||
JANET_THREAD_LOCAL JanetScratch **janet_scratch_mem;
|
||||
JANET_THREAD_LOCAL size_t janet_scratch_cap;
|
||||
JANET_THREAD_LOCAL size_t janet_scratch_len;
|
||||
|
||||
/* Helpers for marking the various gc types */
|
||||
static void janet_mark_funcenv(JanetFuncEnv *env);
|
||||
@@ -49,26 +66,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_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_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;
|
||||
}
|
||||
depth++;
|
||||
} else {
|
||||
@@ -77,7 +119,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) {
|
||||
@@ -85,11 +127,11 @@ static void janet_mark_buffer(JanetBuffer *buffer) {
|
||||
}
|
||||
|
||||
static void janet_mark_abstract(void *adata) {
|
||||
if (janet_gc_reachable(janet_abstract_header(adata)))
|
||||
if (janet_gc_reachable(janet_abstract_head(adata)))
|
||||
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));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +162,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);
|
||||
@@ -132,16 +174,16 @@ static void janet_mark_table(JanetTable *table) {
|
||||
}
|
||||
|
||||
static void janet_mark_struct(const JanetKV *st) {
|
||||
if (janet_gc_reachable(janet_struct_raw(st)))
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -150,7 +192,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 {
|
||||
@@ -181,11 +226,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) {
|
||||
@@ -195,6 +243,13 @@ recur:
|
||||
if (janet_gc_reachable(fiber))
|
||||
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);
|
||||
|
||||
i = fiber->frame;
|
||||
j = fiber->stackstart - JANET_FRAME_SIZE;
|
||||
while (i > 0) {
|
||||
@@ -209,6 +264,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;
|
||||
@@ -217,21 +281,19 @@ 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);
|
||||
free(((JanetArray *) mem)->data);
|
||||
break;
|
||||
case JANET_MEMORY_TABLE:
|
||||
janet_table_deinit((JanetTable*) mem);
|
||||
free(((JanetTable *) mem)->data);
|
||||
break;
|
||||
case JANET_MEMORY_FIBER:
|
||||
free(((JanetFiber *)mem)->data);
|
||||
@@ -239,44 +301,46 @@ static void janet_deinit_block(JanetGCMemoryHeader *block) {
|
||||
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)
|
||||
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);
|
||||
free(def->closure_bitset);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
@@ -291,29 +355,47 @@ void janet_sweep() {
|
||||
|
||||
/* 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);
|
||||
mem = 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->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);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
/* Free all allocated scratch memory */
|
||||
static void janet_free_all_scratch(void) {
|
||||
for (size_t i = 0; i < janet_scratch_len; i++) {
|
||||
free_one_scratch(janet_scratch_mem[i]);
|
||||
}
|
||||
janet_scratch_len = 0;
|
||||
}
|
||||
|
||||
static JanetScratch *janet_mem2scratch(void *mem) {
|
||||
JanetScratch *s = (JanetScratch *)mem;
|
||||
return s - 1;
|
||||
}
|
||||
|
||||
/* Run garbage collection */
|
||||
@@ -321,7 +403,19 @@ void janet_collect(void) {
|
||||
uint32_t i;
|
||||
if (janet_vm_gc_suspend) return;
|
||||
depth = JANET_RECURSION_GUARD;
|
||||
/* 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) {
|
||||
@@ -330,15 +424,16 @@ void janet_collect(void) {
|
||||
}
|
||||
janet_sweep();
|
||||
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;
|
||||
size_t newcount = janet_vm_root_count + 1;
|
||||
if (newcount > janet_vm_root_capacity) {
|
||||
uint32_t newcap = 2 * newcount;
|
||||
size_t newcap = 2 * newcount;
|
||||
janet_vm_roots = realloc(janet_vm_roots, sizeof(Janet) * newcap);
|
||||
if (NULL == janet_vm_roots) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
@@ -354,14 +449,11 @@ 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. */
|
||||
return 1;
|
||||
case JANET_INTEGER:
|
||||
return janet_unwrap_integer(lhs) == janet_unwrap_integer(rhs);
|
||||
case JANET_REAL:
|
||||
return janet_unwrap_real(lhs) == janet_unwrap_real(rhs);
|
||||
default:
|
||||
return janet_unwrap_pointer(lhs) == janet_unwrap_pointer(rhs);
|
||||
}
|
||||
@@ -371,9 +463,8 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
|
||||
* 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;
|
||||
/* 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];
|
||||
return 1;
|
||||
@@ -385,10 +476,9 @@ 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;
|
||||
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];
|
||||
vtop--;
|
||||
@@ -400,16 +490,93 @@ int janet_gcunrootall(Janet root) {
|
||||
|
||||
/* Free all allocated memory */
|
||||
void janet_clear_memory(void) {
|
||||
JanetGCMemoryHeader *current = janet_vm_blocks;
|
||||
JanetGCObject *current = janet_vm_blocks;
|
||||
while (NULL != current) {
|
||||
janet_deinit_block(current);
|
||||
JanetGCMemoryHeader *next = current->next;
|
||||
JanetGCObject *next = current->next;
|
||||
free(current);
|
||||
current = next;
|
||||
}
|
||||
janet_vm_blocks = NULL;
|
||||
janet_free_all_scratch();
|
||||
free(janet_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 = malloc(sizeof(JanetScratch) + size);
|
||||
if (NULL == s) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
s->finalize = NULL;
|
||||
if (janet_scratch_len == janet_scratch_cap) {
|
||||
size_t newcap = 2 * janet_scratch_cap + 2;
|
||||
JanetScratch **newmem = (JanetScratch **) realloc(janet_scratch_mem, newcap * sizeof(JanetScratch));
|
||||
if (NULL == newmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_scratch_cap = newcap;
|
||||
janet_scratch_mem = newmem;
|
||||
}
|
||||
janet_scratch_mem[janet_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_scratch_len) {
|
||||
for (size_t i = janet_scratch_len - 1; ; i--) {
|
||||
if (janet_scratch_mem[i] == s) {
|
||||
JanetScratch *news = realloc(s, size + sizeof(JanetScratch));
|
||||
if (NULL == news) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_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_scratch_len) {
|
||||
for (size_t i = janet_scratch_len - 1; ; i--) {
|
||||
if (janet_scratch_mem[i] == s) {
|
||||
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len];
|
||||
free_one_scratch(s);
|
||||
return;
|
||||
}
|
||||
if (i == 0) break;
|
||||
}
|
||||
}
|
||||
JANET_EXIT("invalid janet_sfree");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2020 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
|
||||
@@ -23,10 +23,13 @@
|
||||
#ifndef JANET_GC_H
|
||||
#define JANET_GC_H
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#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
|
||||
@@ -36,16 +39,8 @@
|
||||
#define janet_gc_type(m) (janet_gc_header(m)->flags & 0xFF)
|
||||
|
||||
#define janet_gc_mark(m) (janet_gc_header(m)->flags |= JANET_MEM_REACHABLE)
|
||||
#define janet_gc_unmark(m) (janet_gc_header(m)->flags &= ~JANET_MEM_COLOR)
|
||||
#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,
|
||||
|
||||
529
src/core/inttypes.c
Normal file
529
src/core/inttypes.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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("bad s64 initializer: %t", 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("bad u64 initializer: %t", 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);
|
||||
}
|
||||
|
||||
static Janet cfun_it_s64_new(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_s64(janet_unwrap_s64(argv[0]));
|
||||
}
|
||||
|
||||
static Janet cfun_it_u64_new(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_u64(janet_unwrap_u64(argv[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
#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++) \
|
||||
*box oper##= janet_unwrap_##type(argv[i]); \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define OPMETHODINVERT(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||
janet_fixarity(argc, 2); \
|
||||
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||
*box = janet_unwrap_##type(argv[1]); \
|
||||
*box oper##= janet_unwrap_##type(argv[0]); \
|
||||
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) janet_panic("division by zero"); \
|
||||
*box oper##= value; \
|
||||
} \
|
||||
return janet_wrap_abstract(box); \
|
||||
} \
|
||||
|
||||
#define DIVMETHODINVERT(T, type, name, oper) \
|
||||
static Janet cfun_it_##type##_##name(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) janet_panic("division by zero"); \
|
||||
*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) janet_panic("division by zero"); \
|
||||
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(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) janet_panic("division by zero"); \
|
||||
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_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]);
|
||||
int64_t x = op1 % op2;
|
||||
*box = (op1 > 0)
|
||||
? ((op2 > 0) ? x : (0 == x ? x : x + op2))
|
||||
: ((op2 > 0) ? (0 == x ? x : x + op2) : x);
|
||||
return janet_wrap_abstract(box);
|
||||
}
|
||||
|
||||
OPMETHOD(int64_t, s64, add, +)
|
||||
OPMETHOD(int64_t, s64, sub, -)
|
||||
OPMETHODINVERT(int64_t, s64, subi, -)
|
||||
OPMETHOD(int64_t, s64, mul, *)
|
||||
DIVMETHOD_SIGNED(int64_t, s64, div, /)
|
||||
DIVMETHOD_SIGNED(int64_t, s64, rem, %)
|
||||
DIVMETHODINVERT_SIGNED(int64_t, s64, divi, /)
|
||||
OPMETHOD(int64_t, s64, and, &)
|
||||
OPMETHOD(int64_t, s64, or, |)
|
||||
OPMETHOD(int64_t, s64, xor, ^)
|
||||
OPMETHOD(int64_t, s64, lshift, <<)
|
||||
OPMETHOD(int64_t, s64, rshift, >>)
|
||||
OPMETHOD(uint64_t, u64, add, +)
|
||||
OPMETHOD(uint64_t, u64, sub, -)
|
||||
OPMETHODINVERT(uint64_t, u64, subi, -)
|
||||
OPMETHOD(uint64_t, u64, mul, *)
|
||||
DIVMETHOD(uint64_t, u64, div, /)
|
||||
DIVMETHOD(uint64_t, u64, mod, %)
|
||||
DIVMETHODINVERT(uint64_t, u64, divi, /)
|
||||
OPMETHOD(uint64_t, u64, and, &)
|
||||
OPMETHOD(uint64_t, u64, or, |)
|
||||
OPMETHOD(uint64_t, u64, xor, ^)
|
||||
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},
|
||||
{"mod", cfun_it_s64_mod},
|
||||
{"rmod", cfun_it_s64_mod},
|
||||
{"%", cfun_it_s64_rem},
|
||||
{"r%", cfun_it_s64_rem},
|
||||
{"&", 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_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},
|
||||
{"mod", cfun_it_u64_mod},
|
||||
{"rmod", cfun_it_u64_mod},
|
||||
{"%", cfun_it_u64_mod},
|
||||
{"r%", cfun_it_u64_mod},
|
||||
{"&", 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_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);
|
||||
}
|
||||
|
||||
static const JanetReg it_cfuns[] = {
|
||||
{
|
||||
"int/s64", cfun_it_s64_new,
|
||||
JDOC("(int/s64 value)\n\n"
|
||||
"Create a boxed signed 64 bit integer from a string value.")
|
||||
},
|
||||
{
|
||||
"int/u64", cfun_it_u64_new,
|
||||
JDOC("(int/u64 value)\n\n"
|
||||
"Create a boxed unsigned 64 bit integer from a string value.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_inttypes(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, it_cfuns);
|
||||
janet_register_abstract_type(&janet_s64_type);
|
||||
janet_register_abstract_type(&janet_u64_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
1051
src/core/io.c
1051
src/core/io.c
File diff suppressed because it is too large
Load Diff
1525
src/core/marsh.c
1525
src/core/marsh.c
File diff suppressed because it is too large
Load Diff
583
src/core/math.c
583
src/core/math.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Calvin Rose
|
||||
* Copyright (c) 2021 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,79 +20,224 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static JANET_THREAD_LOCAL JanetRNG janet_vm_rng = {0, 0, 0, 0, 0};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static Janet cfun_rng_make(int32_t argc, Janet *argv) {
|
||||
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);
|
||||
}
|
||||
|
||||
static Janet cfun_rng_uniform(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||
return janet_wrap_number(janet_rng_double(rng));
|
||||
}
|
||||
|
||||
static Janet cfun_rng_int(int32_t argc, Janet *argv) {
|
||||
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;
|
||||
}
|
||||
|
||||
static Janet cfun_rng_buffer(int32_t argc, Janet *argv) {
|
||||
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 */
|
||||
int janet_rand(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 0);
|
||||
double r = (rand() % RAND_MAX) / ((double) RAND_MAX);
|
||||
JANET_RETURN_REAL(args, r);
|
||||
static Janet janet_rand(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_number(janet_rng_double(&janet_vm_rng));
|
||||
}
|
||||
|
||||
/* Seed the random number generator */
|
||||
int janet_srand(JanetArgs args) {
|
||||
int32_t x = 0;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_INTEGER(x, args, 0);
|
||||
srand((unsigned) x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert a number to an integer */
|
||||
int janet_int(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 1);
|
||||
switch (janet_type(args.v[0])) {
|
||||
default:
|
||||
JANET_THROW(args, "could not convert to integer");
|
||||
case JANET_REAL:
|
||||
*args.ret = janet_wrap_integer((int32_t) janet_unwrap_real(args.v[0]));
|
||||
break;
|
||||
case JANET_INTEGER:
|
||||
*args.ret = args.v[0];
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert a number to a real number */
|
||||
int janet_real(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 1);
|
||||
switch (janet_type(args.v[0])) {
|
||||
default:
|
||||
JANET_THROW(args, "could not convert to real");
|
||||
case JANET_REAL:
|
||||
*args.ret = args.v[0];
|
||||
break;
|
||||
case JANET_INTEGER:
|
||||
*args.ret = janet_wrap_real((double) janet_unwrap_integer(args.v[0]));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int janet_remainder(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 2);
|
||||
if (janet_checktype(args.v[0], JANET_INTEGER) &&
|
||||
janet_checktype(args.v[1], JANET_INTEGER)) {
|
||||
int32_t x, y;
|
||||
x = janet_unwrap_integer(args.v[0]);
|
||||
y = janet_unwrap_integer(args.v[1]);
|
||||
JANET_RETURN_INTEGER(args, x % y);
|
||||
static Janet janet_srand(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
if (janet_checkint(argv[0])) {
|
||||
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
|
||||
janet_rng_seed(&janet_vm_rng, seed);
|
||||
} else {
|
||||
double x, y;
|
||||
JANET_ARG_NUMBER(x, args, 0);
|
||||
JANET_ARG_NUMBER(y, args, 1);
|
||||
JANET_RETURN_REAL(args, fmod(x, y));
|
||||
JanetByteView bytes = janet_getbytes(argv, 0);
|
||||
janet_rng_longseed(&janet_vm_rng, bytes.bytes, bytes.len);
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
#define JANET_DEFINE_MATHOP(name, fop)\
|
||||
int janet_##name(JanetArgs args) {\
|
||||
double x;\
|
||||
JANET_FIXARITY(args, 1);\
|
||||
JANET_ARG_NUMBER(x, args, 0);\
|
||||
JANET_RETURN_REAL(args, fop(x));\
|
||||
static Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
janet_fixarity(argc, 1); \
|
||||
double x = janet_getnumber(argv, 0); \
|
||||
return janet_wrap_number(fop(x)); \
|
||||
}
|
||||
|
||||
JANET_DEFINE_MATHOP(acos, acos)
|
||||
@@ -100,123 +245,283 @@ JANET_DEFINE_MATHOP(asin, asin)
|
||||
JANET_DEFINE_MATHOP(atan, atan)
|
||||
JANET_DEFINE_MATHOP(cos, cos)
|
||||
JANET_DEFINE_MATHOP(cosh, cosh)
|
||||
JANET_DEFINE_MATHOP(acosh, acosh)
|
||||
JANET_DEFINE_MATHOP(sin, sin)
|
||||
JANET_DEFINE_MATHOP(sinh, sinh)
|
||||
JANET_DEFINE_MATHOP(asinh, asinh)
|
||||
JANET_DEFINE_MATHOP(tan, tan)
|
||||
JANET_DEFINE_MATHOP(tanh, tanh)
|
||||
JANET_DEFINE_MATHOP(atanh, atanh)
|
||||
JANET_DEFINE_MATHOP(exp, exp)
|
||||
JANET_DEFINE_MATHOP(exp2, exp2)
|
||||
JANET_DEFINE_MATHOP(expm1, expm1)
|
||||
JANET_DEFINE_MATHOP(log, log)
|
||||
JANET_DEFINE_MATHOP(log10, log10)
|
||||
JANET_DEFINE_MATHOP(log2, log2)
|
||||
JANET_DEFINE_MATHOP(sqrt, sqrt)
|
||||
JANET_DEFINE_MATHOP(cbrt, cbrt)
|
||||
JANET_DEFINE_MATHOP(ceil, ceil)
|
||||
JANET_DEFINE_MATHOP(fabs, fabs)
|
||||
JANET_DEFINE_MATHOP(floor, floor)
|
||||
JANET_DEFINE_MATHOP(trunc, trunc)
|
||||
JANET_DEFINE_MATHOP(round, round)
|
||||
JANET_DEFINE_MATHOP(gamma, lgamma)
|
||||
JANET_DEFINE_MATHOP(log1p, log1p)
|
||||
JANET_DEFINE_MATHOP(erf, erf)
|
||||
JANET_DEFINE_MATHOP(erfc, erfc)
|
||||
|
||||
#define JANET_DEFINE_MATH2OP(name, fop)\
|
||||
int janet_##name(JanetArgs args) {\
|
||||
double lhs, rhs;\
|
||||
JANET_FIXARITY(args, 2);\
|
||||
JANET_ARG_NUMBER(lhs, args, 0);\
|
||||
JANET_ARG_NUMBER(rhs, args, 1);\
|
||||
JANET_RETURN_REAL(args, fop(lhs, rhs));\
|
||||
static Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||
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(hypot, hypot)
|
||||
JANET_DEFINE_MATH2OP(nextafter, nextafter)
|
||||
|
||||
static int janet_not(JanetArgs args) {
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_RETURN_BOOLEAN(args, !janet_truthy(args.v[0]));
|
||||
static Janet janet_not(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_boolean(!janet_truthy(argv[0]));
|
||||
}
|
||||
|
||||
static const JanetReg cfuns[] = {
|
||||
{"%", janet_remainder,
|
||||
"(% dividend divisor)\n\n"
|
||||
"Returns the remainder of dividend / divisor."
|
||||
static const JanetReg math_cfuns[] = {
|
||||
{
|
||||
"not", janet_not,
|
||||
JDOC("(not x)\n\nReturns the boolean inverse of x.")
|
||||
},
|
||||
{"not", janet_not,
|
||||
"(not x)\n\nReturns the boolen inverse of x."
|
||||
{
|
||||
"math/random", janet_rand,
|
||||
JDOC("(math/random)\n\n"
|
||||
"Returns a uniformly distributed random number between 0 and 1.")
|
||||
},
|
||||
{"int", janet_int,
|
||||
"(int x)\n\nCast a number x to an integer."
|
||||
{
|
||||
"math/seedrandom", janet_srand,
|
||||
JDOC("(math/seedrandom seed)\n\n"
|
||||
"Set the seed for the random number generator. seed should be "
|
||||
"an integer or a buffer.")
|
||||
},
|
||||
{"real", janet_real,
|
||||
"(real x)\n\nCast a number x to a real number."
|
||||
{
|
||||
"math/cos", janet_cos,
|
||||
JDOC("(math/cos x)\n\n"
|
||||
"Returns the cosine of x.")
|
||||
},
|
||||
{"math/random", janet_rand,
|
||||
"(math/random)\n\n"
|
||||
"Returns a uniformly distrbuted random real number between 0 and 1."
|
||||
{
|
||||
"math/sin", janet_sin,
|
||||
JDOC("(math/sin x)\n\n"
|
||||
"Returns the sine of x.")
|
||||
},
|
||||
{"math/seedrandom", janet_srand,
|
||||
"(math/seedrandom seed)\n\n"
|
||||
"Set the seed for the random number generator. 'seed' should be an "
|
||||
"an integer."
|
||||
{
|
||||
"math/tan", janet_tan,
|
||||
JDOC("(math/tan x)\n\n"
|
||||
"Returns the tangent of x.")
|
||||
},
|
||||
{"math/cos", janet_cos,
|
||||
"(math/cos x)\n\n"
|
||||
"Returns the cosine of x."
|
||||
{
|
||||
"math/acos", janet_acos,
|
||||
JDOC("(math/acos x)\n\n"
|
||||
"Returns the arccosine of x.")
|
||||
},
|
||||
{"math/sin", janet_sin,
|
||||
"(math/sin x)\n\n"
|
||||
"Returns the sine of x."
|
||||
{
|
||||
"math/asin", janet_asin,
|
||||
JDOC("(math/asin x)\n\n"
|
||||
"Returns the arcsine of x.")
|
||||
},
|
||||
{"math/tan", janet_tan,
|
||||
"(math/tan x)\n\n"
|
||||
"Returns the tangent of x."
|
||||
{
|
||||
"math/atan", janet_atan,
|
||||
JDOC("(math/atan x)\n\n"
|
||||
"Returns the arctangent of x.")
|
||||
},
|
||||
{"math/acos", janet_acos,
|
||||
"(math/acos x)\n\n"
|
||||
"Returns the arccosine of x."
|
||||
{
|
||||
"math/exp", janet_exp,
|
||||
JDOC("(math/exp x)\n\n"
|
||||
"Returns e to the power of x.")
|
||||
},
|
||||
{"math/asin", janet_asin,
|
||||
"(math/asin x)\n\n"
|
||||
"Returns the arcsine of x."
|
||||
{
|
||||
"math/log", janet_log,
|
||||
JDOC("(math/log x)\n\n"
|
||||
"Returns log base natural number of x.")
|
||||
},
|
||||
{"math/atan", janet_atan,
|
||||
"(math/atan x)\n\n"
|
||||
"Returns the arctangent of x."
|
||||
{
|
||||
"math/log10", janet_log10,
|
||||
JDOC("(math/log10 x)\n\n"
|
||||
"Returns log base 10 of x.")
|
||||
},
|
||||
{"math/exp", janet_exp,
|
||||
"(math/exp x)\n\n"
|
||||
"Returns e to the power of x."
|
||||
{
|
||||
"math/log2", janet_log2,
|
||||
JDOC("(math/log2 x)\n\n"
|
||||
"Returns log base 2 of x.")
|
||||
},
|
||||
{"math/log", janet_log,
|
||||
"(math/log x)\n\n"
|
||||
"Returns log base 2 of x."
|
||||
{
|
||||
"math/sqrt", janet_sqrt,
|
||||
JDOC("(math/sqrt x)\n\n"
|
||||
"Returns the square root of x.")
|
||||
},
|
||||
{"math/log10", janet_log10,
|
||||
"(math/log10 x)\n\n"
|
||||
"Returns log base 10 of x."
|
||||
{
|
||||
"math/cbrt", janet_cbrt,
|
||||
JDOC("(math/cbrt x)\n\n"
|
||||
"Returns the cube root of x.")
|
||||
},
|
||||
{"math/sqrt", janet_sqrt,
|
||||
"(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/floor", janet_floor,
|
||||
"(math/floor x)\n\n"
|
||||
"Returns the largest integer value real 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/ceil", janet_ceil,
|
||||
"(math/ceil x)\n\n"
|
||||
"Returns the smallest integer value real 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.")
|
||||
},
|
||||
{"math/pow", janet_pow,
|
||||
"(math/pow a x)\n\n"
|
||||
"Return a to the power of x."
|
||||
{
|
||||
"math/abs", janet_fabs,
|
||||
JDOC("(math/abs x)\n\n"
|
||||
"Return the absolute value of x.")
|
||||
},
|
||||
{
|
||||
"math/sinh", janet_sinh,
|
||||
JDOC("(math/sinh x)\n\n"
|
||||
"Return the hyperbolic sine of x.")
|
||||
},
|
||||
{
|
||||
"math/cosh", janet_cosh,
|
||||
JDOC("(math/cosh x)\n\n"
|
||||
"Return the hyperbolic cosine of x.")
|
||||
},
|
||||
{
|
||||
"math/tanh", janet_tanh,
|
||||
JDOC("(math/tanh x)\n\n"
|
||||
"Return the hyperbolic tangent of x.")
|
||||
},
|
||||
{
|
||||
"math/atanh", janet_atanh,
|
||||
JDOC("(math/atanh x)\n\n"
|
||||
"Return the hyperbolic arctangent of x.")
|
||||
},
|
||||
{
|
||||
"math/asinh", janet_asinh,
|
||||
JDOC("(math/asinh x)\n\n"
|
||||
"Return the hyperbolic arcsine of x.")
|
||||
},
|
||||
{
|
||||
"math/acosh", janet_acosh,
|
||||
JDOC("(math/acosh x)\n\n"
|
||||
"Return the hyperbolic arccosine of x.")
|
||||
},
|
||||
{
|
||||
"math/atan2", janet_atan2,
|
||||
JDOC("(math/atan2 y x)\n\n"
|
||||
"Return the arctangent of y/x. Works even when x is 0.")
|
||||
},
|
||||
{
|
||||
"math/rng", cfun_rng_make,
|
||||
JDOC("(math/rng &opt seed)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{
|
||||
"math/rng-uniform", cfun_rng_uniform,
|
||||
JDOC("(math/rng-seed rng seed)\n\n"
|
||||
"Extract a random number in the range [0, 1) from the RNG.")
|
||||
},
|
||||
{
|
||||
"math/rng-int", cfun_rng_int,
|
||||
JDOC("(math/rng-int rng &opt max)\n\n"
|
||||
"Extract a random random integer in the range [0, max] from the RNG. If "
|
||||
"no max is given, the default is 2^31 - 1.")
|
||||
},
|
||||
{
|
||||
"math/rng-buffer", cfun_rng_buffer,
|
||||
JDOC("(math/rng-buffer rng n &opt buf)\n\n"
|
||||
"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.")
|
||||
},
|
||||
{
|
||||
"math/hypot", janet_hypot,
|
||||
JDOC("(math/hypot a b)\n\n"
|
||||
"Returns the c from the equation c^2 = a^2 + b^2")
|
||||
},
|
||||
{
|
||||
"math/exp2", janet_exp2,
|
||||
JDOC("(math/exp2 x)\n\n"
|
||||
"Returns 2 to the power of x.")
|
||||
},
|
||||
{
|
||||
"math/log1p", janet_log1p,
|
||||
JDOC("(math/log1p x)\n\n"
|
||||
"Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)")
|
||||
},
|
||||
{
|
||||
"math/gamma", janet_gamma,
|
||||
JDOC("(math/gamma x)\n\n"
|
||||
"Returns gamma(x).")
|
||||
},
|
||||
{
|
||||
"math/erfc", janet_erfc,
|
||||
JDOC("(math/erfc x)\n\n"
|
||||
"Returns the complementary error function of x.")
|
||||
},
|
||||
{
|
||||
"math/erf", janet_erf,
|
||||
JDOC("(math/erf x)\n\n"
|
||||
"Returns the error function of x.")
|
||||
},
|
||||
{
|
||||
"math/expm1", janet_expm1,
|
||||
JDOC("(math/expm1 x)\n\n"
|
||||
"Returns e to the power of x minus 1.")
|
||||
},
|
||||
{
|
||||
"math/trunc", janet_trunc,
|
||||
JDOC("(math/trunc x)\n\n"
|
||||
"Returns the integer between x and 0 nearest to x.")
|
||||
},
|
||||
{
|
||||
"math/round", janet_round,
|
||||
JDOC("(math/round x)\n\n"
|
||||
"Returns the integer nearest to x.")
|
||||
},
|
||||
{
|
||||
"math/next", janet_nextafter,
|
||||
JDOC("(math/next x y)\n\n"
|
||||
"Returns the next representable floating point value after x in the direction of y.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
int janet_lib_math(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, NULL, cfuns);
|
||||
|
||||
janet_def(env, "math/pi", janet_wrap_real(3.1415926535897931),
|
||||
"The value pi.");
|
||||
janet_def(env, "math/e", janet_wrap_real(2.7182818284590451),
|
||||
"The base of the natural log.");
|
||||
janet_def(env, "math/inf", janet_wrap_real(INFINITY),
|
||||
"The real number representing positive infinity");
|
||||
return 0;
|
||||
void janet_lib_math(JanetTable *env) {
|
||||
janet_core_cfuns(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_def(env, "math/-inf", janet_wrap_number(-INFINITY),
|
||||
JDOC("The number representing negative infinity"));
|
||||
janet_def(env, "math/int32-min", janet_wrap_number(INT32_MIN),
|
||||
JDOC("The minimum contiguous integer representable by a 32 bit signed integer"));
|
||||
janet_def(env, "math/int32-max", janet_wrap_number(INT32_MAX),
|
||||
JDOC("The maximum contiguous integer represtenable by a 32 bit signed integer"));
|
||||
janet_def(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE),
|
||||
JDOC("The minimum contiguous integer representable by a double (2^53)"));
|
||||
janet_def(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE),
|
||||
JDOC("The maximum contiguous integer represtenable by a double (-(2^53))"));
|
||||
#ifdef NAN
|
||||
janet_def(env, "math/nan", janet_wrap_number(NAN),
|
||||
#else
|
||||
janet_def(env, "math/nan", janet_wrap_number(0.0 / 0.0),
|
||||
#endif
|
||||
JDOC("Not a number (IEEE-754 NaN)"));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#include <janet/janet.h>
|
||||
#include "compile.h"
|
||||
#include "emit.h"
|
||||
#include "vector.h"
|
||||
|
||||
/* Parse a part of a symbol that can be used for building up code. */
|
||||
static JanetSlot multisym_parse_part(JanetCompiler *c, const uint8_t *sympart, int32_t len) {
|
||||
if (sympart[0] == ':') {
|
||||
return janetc_cslot(janet_symbolv(sympart, len));
|
||||
} else {
|
||||
int err = 0;
|
||||
int32_t num = janet_scan_integer(sympart + 1, len - 1, &err);
|
||||
if (err) {
|
||||
return janetc_resolve(c, janet_symbol(sympart + 1, len - 1));
|
||||
} else {
|
||||
return janetc_cslot(janet_wrap_integer(num));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static JanetSlot multisym_do_parts(JanetFopts opts, int put, const uint8_t *sym, Janet rvalue) {
|
||||
JanetSlot slot;
|
||||
JanetFopts subopts = janetc_fopts_default(opts.compiler);
|
||||
int i, j;
|
||||
for (i = 1, j = 0; sym[i]; i++) {
|
||||
if (sym[i] == ':' || sym[i] == '.') {
|
||||
if (j) {
|
||||
JanetSlot target = janetc_gettarget(subopts);
|
||||
JanetSlot value = multisym_parse_part(opts.compiler, sym + j, i - j);
|
||||
janetc_emit_sss(opts.compiler, JOP_GET, target, slot, value, 1);
|
||||
slot = target;
|
||||
} else {
|
||||
const uint8_t *nextsym = janet_symbol(sym + j, i - j);
|
||||
slot = janetc_resolve(opts.compiler, nextsym);
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (j) {
|
||||
/* multisym (outermost get or put) */
|
||||
JanetSlot target = janetc_gettarget(opts);
|
||||
JanetSlot key = multisym_parse_part(opts.compiler, sym + j, i - j);
|
||||
if (put) {
|
||||
subopts.flags = JANET_FOPTS_HINT;
|
||||
subopts.hint = target;
|
||||
JanetSlot r_slot = janetc_value(subopts, rvalue);
|
||||
janetc_emit_sss(opts.compiler, JOP_PUT, slot, key, r_slot, 0);
|
||||
janetc_copy(opts.compiler, target, r_slot);
|
||||
} else {
|
||||
janetc_emit_sss(opts.compiler, JOP_GET, target, slot, key, 1);
|
||||
}
|
||||
return target;
|
||||
} else {
|
||||
/* normal symbol */
|
||||
if (put) {
|
||||
JanetSlot ret, dest;
|
||||
dest = janetc_resolve(opts.compiler, sym);
|
||||
if (!(dest.flags & JANET_SLOT_MUTABLE)) {
|
||||
janetc_cerror(opts.compiler, "cannot set constant");
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
}
|
||||
subopts.flags = JANET_FOPTS_HINT;
|
||||
subopts.hint = dest;
|
||||
ret = janetc_value(subopts, rvalue);
|
||||
janetc_copy(opts.compiler, dest, ret);
|
||||
return ret;
|
||||
}
|
||||
return janetc_resolve(opts.compiler, sym);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if a symbol is a multisym, and if so, transform
|
||||
* it and emit the code for treating it as a bunch of nested
|
||||
* gets. */
|
||||
JanetSlot janetc_sym_rvalue(JanetFopts opts, const uint8_t *sym) {
|
||||
if (janet_string_length(sym) && sym[0] != ':') {
|
||||
return multisym_do_parts(opts, 0, sym, janet_wrap_nil());
|
||||
} else {
|
||||
/* keyword */
|
||||
return janetc_cslot(janet_wrap_symbol(sym));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if a symbol is a multisym, and if so, transform
|
||||
* it into the correct 'put' expression. */
|
||||
JanetSlot janetc_sym_lvalue(JanetFopts opts, const uint8_t *sym, Janet value) {
|
||||
return multisym_do_parts(opts, 1, sym, value);
|
||||
}
|
||||
732
src/core/net.c
Normal file
732
src/core/net.c
Normal file
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#ifdef JANET_NET
|
||||
|
||||
#include <math.h>
|
||||
#ifdef JANET_WINDOWS
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <mswsock.h>
|
||||
#pragma comment (lib, "Ws2_32.lib")
|
||||
#pragma comment (lib, "Mswsock.lib")
|
||||
#pragma comment (lib, "Advapi32.lib")
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
const JanetAbstractType janet_address_type = {
|
||||
"core/socket-address",
|
||||
JANET_ATEND_NAME
|
||||
};
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
#define JSOCKCLOSE(x) closesocket((SOCKET) x)
|
||||
#define JSOCKDEFAULT INVALID_SOCKET
|
||||
#define JSOCKVALID(x) ((x) != INVALID_SOCKET)
|
||||
#define JSock SOCKET
|
||||
#define JSOCKFLAGS 0
|
||||
#else
|
||||
#define JSOCKCLOSE(x) close(x)
|
||||
#define JSOCKDEFAULT 0
|
||||
#define JSOCKVALID(x) ((x) >= 0)
|
||||
#define JSock int
|
||||
#ifdef SOCK_CLOEXEC
|
||||
#define JSOCKFLAGS SOCK_CLOEXEC
|
||||
#else
|
||||
#define JSOCKFLAGS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static JanetStream *make_stream(JSock handle, uint32_t flags);
|
||||
|
||||
/* We pass this flag to all send calls to prevent sigpipe */
|
||||
#ifndef MSG_NOSIGNAL
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
/* Make sure a socket doesn't block */
|
||||
static void janet_net_socknoblock(JSock s) {
|
||||
#ifdef JANET_WINDOWS
|
||||
unsigned long arg = 1;
|
||||
ioctlsocket(s, FIONBIO, &arg);
|
||||
#else
|
||||
#if !defined(SOCK_CLOEXEC) && defined(O_CLOEXEC)
|
||||
int extra = O_CLOEXEC;
|
||||
#else
|
||||
int extra = 0;
|
||||
#endif
|
||||
fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0) | O_NONBLOCK | extra);
|
||||
#ifdef SO_NOSIGPIPE
|
||||
int enable = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* State machine for accepting connections. */
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
|
||||
typedef struct {
|
||||
JanetListenerState head;
|
||||
WSAOVERLAPPED overlapped;
|
||||
JanetFunction *function;
|
||||
JanetStream *lstream;
|
||||
JanetStream *astream;
|
||||
char buf[1024];
|
||||
} NetStateAccept;
|
||||
|
||||
static int net_sched_accept_impl(NetStateAccept *state, Janet *err);
|
||||
|
||||
JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event) {
|
||||
NetStateAccept *state = (NetStateAccept *)s;
|
||||
switch (event) {
|
||||
default:
|
||||
break;
|
||||
case JANET_ASYNC_EVENT_MARK: {
|
||||
if (state->lstream) janet_mark(janet_wrap_abstract(state->lstream));
|
||||
if (state->astream) janet_mark(janet_wrap_abstract(state->astream));
|
||||
if (state->function) janet_mark(janet_wrap_abstract(state->function));
|
||||
break;
|
||||
}
|
||||
case JANET_ASYNC_EVENT_CLOSE:
|
||||
janet_schedule(s->fiber, janet_wrap_nil());
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
case JANET_ASYNC_EVENT_COMPLETE: {
|
||||
int seconds;
|
||||
int bytes = sizeof(seconds);
|
||||
if (NO_ERROR != getsockopt((SOCKET) state->astream->handle, SOL_SOCKET, SO_CONNECT_TIME,
|
||||
(char *)&seconds, &bytes)) {
|
||||
janet_cancel(s->fiber, janet_cstringv("failed to accept connection"));
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
}
|
||||
if (NO_ERROR != setsockopt((SOCKET) state->astream->handle, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
||||
(char *) & (state->lstream->handle), sizeof(SOCKET))) {
|
||||
janet_cancel(s->fiber, janet_cstringv("failed to accept connection"));
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
}
|
||||
|
||||
Janet streamv = janet_wrap_abstract(state->astream);
|
||||
if (state->function) {
|
||||
/* Schedule worker */
|
||||
JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
|
||||
fiber->supervisor_channel = s->fiber->supervisor_channel;
|
||||
janet_schedule(fiber, janet_wrap_nil());
|
||||
/* Now listen again for next connection */
|
||||
Janet err;
|
||||
if (net_sched_accept_impl(state, &err)) {
|
||||
janet_cancel(s->fiber, err);
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
}
|
||||
} else {
|
||||
janet_schedule(s->fiber, streamv);
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return JANET_ASYNC_STATUS_NOT_DONE;
|
||||
}
|
||||
|
||||
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
|
||||
Janet err;
|
||||
SOCKET lsock = (SOCKET) stream->handle;
|
||||
JanetListenerState *s = janet_listen(stream, net_machine_accept, JANET_ASYNC_LISTEN_READ, sizeof(NetStateAccept), NULL);
|
||||
NetStateAccept *state = (NetStateAccept *)s;
|
||||
memset(&state->overlapped, 0, sizeof(WSAOVERLAPPED));
|
||||
memset(&state->buf, 0, 1024);
|
||||
state->function = fun;
|
||||
state->lstream = stream;
|
||||
s->tag = &state->overlapped;
|
||||
if (net_sched_accept_impl(state, &err)) janet_panicv(err);
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static int net_sched_accept_impl(NetStateAccept *state, Janet *err) {
|
||||
SOCKET lsock = (SOCKET) state->lstream->handle;
|
||||
SOCKET asock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
if (asock == INVALID_SOCKET) {
|
||||
*err = janet_ev_lasterr();
|
||||
return 1;
|
||||
}
|
||||
JanetStream *astream = make_stream(asock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||
state->astream = astream;
|
||||
int socksize = sizeof(SOCKADDR_STORAGE) + 16;
|
||||
if (FALSE == AcceptEx(lsock, asock, state->buf, 0, socksize, socksize, NULL, &state->overlapped)) {
|
||||
int code = WSAGetLastError();
|
||||
if (code == WSA_IO_PENDING) return 0; /* indicates io is happening async */
|
||||
*err = janet_ev_lasterr();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef struct {
|
||||
JanetListenerState head;
|
||||
JanetFunction *function;
|
||||
} NetStateAccept;
|
||||
|
||||
JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event) {
|
||||
NetStateAccept *state = (NetStateAccept *)s;
|
||||
switch (event) {
|
||||
default:
|
||||
break;
|
||||
case JANET_ASYNC_EVENT_MARK: {
|
||||
if (state->function) janet_mark(janet_wrap_function(state->function));
|
||||
break;
|
||||
}
|
||||
case JANET_ASYNC_EVENT_CLOSE:
|
||||
janet_schedule(s->fiber, janet_wrap_nil());
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
case JANET_ASYNC_EVENT_READ: {
|
||||
JSock connfd = accept(s->stream->handle, NULL, NULL);
|
||||
if (JSOCKVALID(connfd)) {
|
||||
janet_net_socknoblock(connfd);
|
||||
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||
Janet streamv = janet_wrap_abstract(stream);
|
||||
if (state->function) {
|
||||
JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
|
||||
fiber->supervisor_channel = s->fiber->supervisor_channel;
|
||||
janet_schedule(fiber, janet_wrap_nil());
|
||||
} else {
|
||||
janet_schedule(s->fiber, streamv);
|
||||
return JANET_ASYNC_STATUS_DONE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return JANET_ASYNC_STATUS_NOT_DONE;
|
||||
}
|
||||
|
||||
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
|
||||
NetStateAccept *state = (NetStateAccept *) janet_listen(stream, net_machine_accept, JANET_ASYNC_LISTEN_READ, sizeof(NetStateAccept), NULL);
|
||||
state->function = fun;
|
||||
janet_await();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* Adress info */
|
||||
|
||||
static int janet_get_sockettype(Janet *argv, int32_t argc, int32_t n) {
|
||||
JanetKeyword stype = janet_optkeyword(argv, argc, n, NULL);
|
||||
int socktype = SOCK_DGRAM;
|
||||
if ((NULL == stype) || !janet_cstrcmp(stype, "stream")) {
|
||||
socktype = SOCK_STREAM;
|
||||
} else if (janet_cstrcmp(stype, "datagram")) {
|
||||
janet_panicf("expected socket type as :stream or :datagram, got %v", argv[n]);
|
||||
}
|
||||
return socktype;
|
||||
}
|
||||
|
||||
/* Needs argc >= offset + 2 */
|
||||
/* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1, otherwise 0 */
|
||||
static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int socktype, int passive, int *is_unix) {
|
||||
/* Unix socket support - not yet supported on windows. */
|
||||
#ifndef JANET_WINDOWS
|
||||
if (janet_keyeq(argv[offset], "unix")) {
|
||||
const char *path = janet_getcstring(argv, offset + 1);
|
||||
struct sockaddr_un *saddr = calloc(1, sizeof(struct sockaddr_un));
|
||||
if (saddr == NULL) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
saddr->sun_family = AF_UNIX;
|
||||
#ifdef JANET_LINUX
|
||||
if (path[0] == '@') {
|
||||
saddr->sun_path[0] = '\0';
|
||||
snprintf(saddr->sun_path + 1, 107, "%s", path + 1);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
snprintf(saddr->sun_path, 108, "%s", path);
|
||||
}
|
||||
*is_unix = 1;
|
||||
return (struct addrinfo *) saddr;
|
||||
}
|
||||
#endif
|
||||
/* Get host and port */
|
||||
const char *host = janet_getcstring(argv, offset);
|
||||
const char *port;
|
||||
if (janet_checkint(argv[offset + 1])) {
|
||||
port = (const char *)janet_to_string(argv[offset + 1]);
|
||||
} else {
|
||||
port = janet_optcstring(argv, offset + 2, offset + 1, NULL);
|
||||
}
|
||||
/* getaddrinfo */
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = socktype;
|
||||
hints.ai_flags = passive ? AI_PASSIVE : 0;
|
||||
int status = getaddrinfo(host, port, &hints, &ai);
|
||||
if (status) {
|
||||
janet_panicf("could not get address info: %s", gai_strerror(status));
|
||||
}
|
||||
*is_unix = 0;
|
||||
return ai;
|
||||
}
|
||||
|
||||
/*
|
||||
* C Funs
|
||||
*/
|
||||
|
||||
static Janet cfun_net_sockaddr(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 4);
|
||||
int socktype = janet_get_sockettype(argv, argc, 2);
|
||||
int is_unix = 0;
|
||||
int make_arr = (argc >= 3 && janet_truthy(argv[3]));
|
||||
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix);
|
||||
#ifndef JANET_WINDOWS
|
||||
/* no unix domain socket support on windows yet */
|
||||
if (is_unix) {
|
||||
void *abst = janet_abstract(&janet_address_type, sizeof(struct sockaddr_un));
|
||||
memcpy(abst, ai, sizeof(struct sockaddr_un));
|
||||
Janet ret = janet_wrap_abstract(abst);
|
||||
return make_arr ? janet_wrap_array(janet_array_n(&ret, 1)) : ret;
|
||||
}
|
||||
#endif
|
||||
if (make_arr) {
|
||||
/* Select all */
|
||||
JanetArray *arr = janet_array(10);
|
||||
struct addrinfo *iter = ai;
|
||||
while (NULL != iter) {
|
||||
void *abst = janet_abstract(&janet_address_type, iter->ai_addrlen);
|
||||
memcpy(abst, iter->ai_addr, iter->ai_addrlen);
|
||||
janet_array_push(arr, janet_wrap_abstract(abst));
|
||||
iter = iter->ai_next;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
return janet_wrap_array(arr);
|
||||
} else {
|
||||
/* Select first */
|
||||
if (NULL == ai) {
|
||||
janet_panic("no data for given address");
|
||||
}
|
||||
void *abst = janet_abstract(&janet_address_type, ai->ai_addrlen);
|
||||
memcpy(abst, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
return janet_wrap_abstract(abst);
|
||||
}
|
||||
}
|
||||
|
||||
static Janet cfun_net_connect(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 3);
|
||||
|
||||
int socktype = janet_get_sockettype(argv, argc, 2);
|
||||
int is_unix = 0;
|
||||
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix);
|
||||
|
||||
/* Create socket */
|
||||
JSock sock = JSOCKDEFAULT;
|
||||
void *addr = NULL;
|
||||
socklen_t addrlen = 0;
|
||||
#ifndef JANET_WINDOWS
|
||||
if (is_unix) {
|
||||
sock = socket(AF_UNIX, socktype | JSOCKFLAGS, 0);
|
||||
if (!JSOCKVALID(sock)) {
|
||||
janet_panicf("could not create socket: %V", janet_ev_lasterr());
|
||||
}
|
||||
addr = (void *) ai;
|
||||
addrlen = sizeof(struct sockaddr_un);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct addrinfo *rp = NULL;
|
||||
for (rp = ai; rp != NULL; rp = rp->ai_next) {
|
||||
#ifdef JANET_WINDOWS
|
||||
sock = WSASocketW(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
#else
|
||||
sock = socket(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol);
|
||||
#endif
|
||||
if (JSOCKVALID(sock)) {
|
||||
addr = rp->ai_addr;
|
||||
addrlen = (socklen_t) rp->ai_addrlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL == addr) {
|
||||
freeaddrinfo(ai);
|
||||
janet_panicf("could not create socket: %V", janet_ev_lasterr());
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect to socket */
|
||||
#ifdef JANET_WINDOWS
|
||||
int status = WSAConnect(sock, addr, addrlen, NULL, NULL, NULL, NULL);
|
||||
freeaddrinfo(ai);
|
||||
#else
|
||||
int status = connect(sock, addr, addrlen);
|
||||
if (is_unix) {
|
||||
free(ai);
|
||||
} else {
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status == -1) {
|
||||
JSOCKCLOSE(sock);
|
||||
janet_panicf("could not connect to socket: %V", janet_ev_lasterr());
|
||||
}
|
||||
|
||||
/* Set up the socket for non-blocking IO after connect - TODO - non-blocking connect? */
|
||||
janet_net_socknoblock(sock);
|
||||
|
||||
/* Wrap socket in abstract type JanetStream */
|
||||
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||
return janet_wrap_abstract(stream);
|
||||
}
|
||||
|
||||
static const char *serverify_socket(JSock sfd) {
|
||||
/* Set various socket options */
|
||||
int enable = 1;
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(int)) < 0) {
|
||||
return "setsockopt(SO_REUSEADDR) failed";
|
||||
}
|
||||
#ifdef SO_REUSEPORT
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
|
||||
return "setsockopt(SO_REUSEPORT) failed";
|
||||
}
|
||||
#endif
|
||||
janet_net_socknoblock(sfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Janet cfun_net_listen(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 3);
|
||||
|
||||
/* Get host, port, and handler*/
|
||||
int socktype = janet_get_sockettype(argv, argc, 2);
|
||||
int is_unix = 0;
|
||||
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 1, &is_unix);
|
||||
|
||||
JSock sfd = JSOCKDEFAULT;
|
||||
#ifndef JANET_WINDOWS
|
||||
if (is_unix) {
|
||||
sfd = socket(AF_UNIX, socktype | JSOCKFLAGS, 0);
|
||||
if (!JSOCKVALID(sfd)) {
|
||||
free(ai);
|
||||
janet_panicf("could not create socket: %V", janet_ev_lasterr());
|
||||
}
|
||||
const char *err = serverify_socket(sfd);
|
||||
if (NULL != err || bind(sfd, (struct sockaddr *)ai, sizeof(struct sockaddr_un))) {
|
||||
JSOCKCLOSE(sfd);
|
||||
free(ai);
|
||||
if (err) {
|
||||
janet_panic(err);
|
||||
} else {
|
||||
janet_panicf("could not bind socket: %V", janet_ev_lasterr());
|
||||
}
|
||||
}
|
||||
free(ai);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* Check all addrinfos in a loop for the first that we can bind to. */
|
||||
struct addrinfo *rp = NULL;
|
||||
for (rp = ai; rp != NULL; rp = rp->ai_next) {
|
||||
#ifdef JANET_WINDOWS
|
||||
sfd = WSASocketW(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
#else
|
||||
sfd = socket(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol);
|
||||
#endif
|
||||
if (!JSOCKVALID(sfd)) continue;
|
||||
const char *err = serverify_socket(sfd);
|
||||
if (NULL != err) {
|
||||
JSOCKCLOSE(sfd);
|
||||
continue;
|
||||
}
|
||||
/* Bind */
|
||||
if (bind(sfd, rp->ai_addr, (int) rp->ai_addrlen) == 0) break;
|
||||
JSOCKCLOSE(sfd);
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if (NULL == rp) {
|
||||
janet_panic("could not bind to any sockets");
|
||||
}
|
||||
}
|
||||
|
||||
if (socktype == SOCK_DGRAM) {
|
||||
/* Datagram server (UDP) */
|
||||
JanetStream *stream = make_stream(sfd, JANET_STREAM_UDPSERVER | JANET_STREAM_READABLE);
|
||||
return janet_wrap_abstract(stream);
|
||||
} else {
|
||||
/* Stream server (TCP) */
|
||||
|
||||
/* listen */
|
||||
int status = listen(sfd, 1024);
|
||||
if (status) {
|
||||
JSOCKCLOSE(sfd);
|
||||
janet_panicf("could not listen on file descriptor: %V", janet_ev_lasterr());
|
||||
}
|
||||
|
||||
/* Put sfd on our loop */
|
||||
JanetStream *stream = make_stream(sfd, JANET_STREAM_ACCEPTABLE);
|
||||
return janet_wrap_abstract(stream);
|
||||
}
|
||||
}
|
||||
|
||||
static Janet cfun_stream_accept_loop(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_ACCEPTABLE | JANET_STREAM_SOCKET);
|
||||
JanetFunction *fun = janet_getfunction(argv, 1);
|
||||
janet_sched_accept(stream, fun);
|
||||
}
|
||||
|
||||
static Janet cfun_stream_accept(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_ACCEPTABLE | JANET_STREAM_SOCKET);
|
||||
double to = janet_optnumber(argv, argc, 1, INFINITY);
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_sched_accept(stream, NULL);
|
||||
}
|
||||
|
||||
static Janet cfun_stream_read(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 4);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_READABLE | JANET_STREAM_SOCKET);
|
||||
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, 10);
|
||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||
if (janet_keyeq(argv[1], "all")) {
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_recvchunk(stream, buffer, INT32_MAX, MSG_NOSIGNAL);
|
||||
} else {
|
||||
int32_t n = janet_getnat(argv, 1);
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_recv(stream, buffer, n, MSG_NOSIGNAL);
|
||||
}
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static Janet cfun_stream_chunk(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 4);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_READABLE | JANET_STREAM_SOCKET);
|
||||
int32_t n = janet_getnat(argv, 1);
|
||||
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, 10);
|
||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_recvchunk(stream, buffer, n, MSG_NOSIGNAL);
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static Janet cfun_stream_recv_from(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 3, 4);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_UDPSERVER | JANET_STREAM_SOCKET);
|
||||
int32_t n = janet_getnat(argv, 1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 2);
|
||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_recvfrom(stream, buffer, n, MSG_NOSIGNAL);
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static Janet cfun_stream_write(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_WRITABLE | JANET_STREAM_SOCKET);
|
||||
double to = janet_optnumber(argv, argc, 2, INFINITY);
|
||||
if (janet_checktype(argv[1], JANET_BUFFER)) {
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_send_buffer(stream, janet_getbuffer(argv, 1), MSG_NOSIGNAL);
|
||||
} else {
|
||||
JanetByteView bytes = janet_getbytes(argv, 1);
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_send_string(stream, bytes.bytes, MSG_NOSIGNAL);
|
||||
}
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static Janet cfun_stream_send_to(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 3, 4);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_UDPSERVER | JANET_STREAM_SOCKET);
|
||||
void *dest = janet_getabstract(argv, 1, &janet_address_type);
|
||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||
if (janet_checktype(argv[2], JANET_BUFFER)) {
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_sendto_buffer(stream, janet_getbuffer(argv, 2), dest, MSG_NOSIGNAL);
|
||||
} else {
|
||||
JanetByteView bytes = janet_getbytes(argv, 2);
|
||||
if (to != INFINITY) janet_addtimeout(to);
|
||||
janet_ev_sendto_string(stream, bytes.bytes, dest, MSG_NOSIGNAL);
|
||||
}
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static Janet cfun_stream_flush(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||
janet_stream_flags(stream, JANET_STREAM_WRITABLE | JANET_STREAM_SOCKET);
|
||||
/* Toggle no delay flag */
|
||||
int flag = 1;
|
||||
setsockopt((JSock) stream->handle, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
|
||||
flag = 0;
|
||||
setsockopt((JSock) stream->handle, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static const JanetMethod net_stream_methods[] = {
|
||||
{"chunk", cfun_stream_chunk},
|
||||
{"close", janet_cfun_stream_close},
|
||||
{"read", cfun_stream_read},
|
||||
{"write", cfun_stream_write},
|
||||
{"flush", cfun_stream_flush},
|
||||
{"accept", cfun_stream_accept},
|
||||
{"accept-loop", cfun_stream_accept_loop},
|
||||
{"send-to", cfun_stream_send_to},
|
||||
{"recv-from", cfun_stream_recv_from},
|
||||
{"recv-from", cfun_stream_recv_from},
|
||||
{"evread", janet_cfun_stream_read},
|
||||
{"evchunk", janet_cfun_stream_chunk},
|
||||
{"evwrite", janet_cfun_stream_write},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static JanetStream *make_stream(JSock handle, uint32_t flags) {
|
||||
return janet_stream((JanetHandle) handle, flags | JANET_STREAM_SOCKET, net_stream_methods);
|
||||
}
|
||||
|
||||
static const JanetReg net_cfuns[] = {
|
||||
{
|
||||
"net/address", cfun_net_sockaddr,
|
||||
JDOC("(net/address host port &opt type)\n\n"
|
||||
"Look up the connection information for a given hostname, port, and connection type. Returns "
|
||||
"a handle that can be used to send datagrams over network without establishing a connection. "
|
||||
"On Posix platforms, you can use :unix for host to connect to a unix domain socket, where the name is "
|
||||
"given in the port argument. On Linux, abstract "
|
||||
"unix domain sockets are specified with a leading '@' character in port.")
|
||||
},
|
||||
{
|
||||
"net/listen", cfun_net_listen,
|
||||
JDOC("(net/listen host port &opt type)\n\n"
|
||||
"Creates a server. Returns a new stream that is neither readable nor "
|
||||
"writeable. Use net/accept or net/accept-loop be to handle connections and start the server. "
|
||||
"The type parameter specifies the type of network connection, either "
|
||||
"a :stream (usually tcp), or :datagram (usually udp). If not specified, the default is "
|
||||
":stream. The host and port arguments are the same as in net/address.")
|
||||
},
|
||||
{
|
||||
"net/accept", cfun_stream_accept,
|
||||
JDOC("(net/accept stream &opt timeout)\n\n"
|
||||
"Get the next connection on a server stream. This would usually be called in a loop in a dedicated fiber. "
|
||||
"Takes an optional timeout in seconds, after which will return nil. "
|
||||
"Returns a new duplex stream which represents a connection to the client.")
|
||||
},
|
||||
{
|
||||
"net/accept-loop", cfun_stream_accept_loop,
|
||||
JDOC("(net/accept-loop stream handler)\n\n"
|
||||
"Shorthand for running a server stream that will continuously accept new connections. "
|
||||
"Blocks the current fiber until the stream is closed, and will return the stream.")
|
||||
},
|
||||
{
|
||||
"net/read", cfun_stream_read,
|
||||
JDOC("(net/read stream nbytes &opt buf timeout)\n\n"
|
||||
"Read up to n bytes from a stream, suspending the current fiber until the bytes are available. "
|
||||
"`n` can also be the keyword `:all` to read into the buffer until end of stream. "
|
||||
"If less than n bytes are available (and more than 0), will push those bytes and return early. "
|
||||
"Takes an optional timeout in seconds, after which will return nil. "
|
||||
"Returns a buffer with up to n more bytes in it, or raises an error if the read failed.")
|
||||
},
|
||||
{
|
||||
"net/chunk", cfun_stream_chunk,
|
||||
JDOC("(net/chunk stream nbytes &opt buf timeout)\n\n"
|
||||
"Same a net/read, but will wait for all n bytes to arrive rather than return early. "
|
||||
"Takes an optional timeout in seconds, after which will return nil.")
|
||||
},
|
||||
{
|
||||
"net/write", cfun_stream_write,
|
||||
JDOC("(net/write stream data &opt timeout)\n\n"
|
||||
"Write data to a stream, suspending the current fiber until the write "
|
||||
"completes. Takes an optional timeout in seconds, after which will return nil. "
|
||||
"Returns nil, or raises an error if the write failed.")
|
||||
},
|
||||
{
|
||||
"net/send-to", cfun_stream_send_to,
|
||||
JDOC("(net/send-to stream dest data &opt timeout)\n\n"
|
||||
"Writes a datagram to a server stream. dest is a the destination address of the packet. "
|
||||
"Takes an optional timeout in seconds, after which will return nil. "
|
||||
"Returns stream.")
|
||||
},
|
||||
{
|
||||
"net/recv-from", cfun_stream_recv_from,
|
||||
JDOC("(net/recv-from stream nbytes buf &opt timoeut)\n\n"
|
||||
"Receives data from a server stream and puts it into a buffer. Returns the socket-address the "
|
||||
"packet came from. Takes an optional timeout in seconds, after which will return nil.")
|
||||
},
|
||||
{
|
||||
"net/flush", cfun_stream_flush,
|
||||
JDOC("(net/flush stream)\n\n"
|
||||
"Make sure that a stream is not buffering any data. This temporarily disables Nagle's algorithm. "
|
||||
"Use this to make sure data is sent without delay. Returns stream.")
|
||||
},
|
||||
{
|
||||
"net/connect", cfun_net_connect,
|
||||
JDOC("(net/connect host port &opt type)\n\n"
|
||||
"Open a connection to communicate with a server. Returns a duplex stream "
|
||||
"that can be used to communicate with the server. Type is an optional keyword "
|
||||
"to specify a connection type, either :stream or :datagram. The default is :stream. ")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void janet_lib_net(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, net_cfuns);
|
||||
}
|
||||
|
||||
void janet_net_init(void) {
|
||||
#ifdef JANET_WINDOWS
|
||||
WSADATA wsaData;
|
||||
janet_assert(!WSAStartup(MAKEWORD(2, 2), &wsaData), "could not start winsock");
|
||||
#endif
|
||||
}
|
||||
|
||||
void janet_net_deinit(void) {
|
||||
#ifdef JANET_WINDOWS
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
2430
src/core/os.c
2430
src/core/os.c
File diff suppressed because it is too large
Load Diff
1092
src/core/parse.c
1092
src/core/parse.c
File diff suppressed because it is too large
Load Diff
1704
src/core/peg.c
Normal file
1704
src/core/peg.c
Normal file
File diff suppressed because it is too large
Load Diff
1011
src/core/pp.c
Normal file
1011
src/core/pp.c
Normal file
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