mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-10 12:10:16 +00:00
Compare commits
621 Commits
981e6e6e88
...
76c251fb7f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76c251fb7f | ||
|
|
4462391daa | ||
|
|
ca459f6b65 | ||
|
|
d3a851fb46 | ||
|
|
467b3b4dba | ||
|
|
f76ba54e9f | ||
|
|
807b8a417d | ||
|
|
eb1147826e | ||
|
|
66f7bbd18c | ||
|
|
145782b789 | ||
|
|
0e7936341b | ||
|
|
2930da4e7f | ||
|
|
1b5b9fa6cb | ||
|
|
c4c7b9ef25 | ||
|
|
0f5ce54c66 | ||
|
|
88f893ddd7 | ||
|
|
76075de70c | ||
|
|
c9e688207a | ||
|
|
f27548c6df | ||
|
|
34d620c82f | ||
|
|
b51bf33572 | ||
|
|
0806b1aee1 | ||
|
|
87bf0c9e7c | ||
|
|
a96173fd6a | ||
|
|
d8f2808462 | ||
|
|
3e99f46273 | ||
|
|
3caca62f2c | ||
|
|
2eb3eabcc2 | ||
|
|
3fbbd9fb67 | ||
|
|
651bf997fc | ||
|
|
46fb524a01 | ||
|
|
41a938386a | ||
|
|
ad1482370b | ||
|
|
4829568c87 | ||
|
|
81edd22a76 | ||
|
|
471d4ae578 | ||
|
|
22d4c07f50 | ||
|
|
cd3c28fdd8 | ||
|
|
f481337f98 | ||
|
|
8264f125d6 | ||
|
|
b6993532fa | ||
|
|
1c1e898950 | ||
|
|
6805b418b5 | ||
|
|
3a2e8ab6c5 | ||
|
|
c4f761d7c2 | ||
|
|
e94cfaf42e | ||
|
|
749435e516 | ||
|
|
f756bd813d | ||
|
|
bf5fe3d898 | ||
|
|
f9a1bd1d49 | ||
|
|
0bd25e7224 | ||
|
|
ceb49d832b | ||
|
|
6a7da5a1d5 | ||
|
|
65295f3e29 | ||
|
|
56097f6927 | ||
|
|
7ca97f03a7 | ||
|
|
ee29eadcd3 | ||
|
|
4254de48bf | ||
|
|
693026c6c4 | ||
|
|
33bea83e53 | ||
|
|
26f53bf85d | ||
|
|
f28335f1f7 | ||
|
|
9fbaca3b13 | ||
|
|
4e8920b280 | ||
|
|
0918256c90 | ||
|
|
90eb50a3a5 | ||
|
|
1735e0d3b8 | ||
|
|
50ec46fe83 | ||
|
|
0c081ba912 | ||
|
|
7215f48007 | ||
|
|
aa3be3b63d | ||
|
|
04804ad410 | ||
|
|
0b649f3bef | ||
|
|
a87641c04d | ||
|
|
9c173fdada | ||
|
|
348bb2b7a5 | ||
|
|
39947e8f15 | ||
|
|
56763e05f9 | ||
|
|
cd9a9f7119 | ||
|
|
ea9dabdf99 | ||
|
|
b1a8c6db8e | ||
|
|
3c87bf8630 | ||
|
|
8e1e29ddd6 | ||
|
|
205f6ff225 | ||
|
|
397123e3c9 | ||
|
|
e04d4e790c | ||
|
|
8eff9abfbc | ||
|
|
ab3a9b7584 | ||
|
|
d835ea984e | ||
|
|
9162e84ae6 | ||
|
|
6c6e4f0512 | ||
|
|
b7950d4a11 | ||
|
|
9c028fd133 | ||
|
|
a648313fb7 | ||
|
|
66cefad078 | ||
|
|
ccca4791ae | ||
|
|
3bbcb384bd | ||
|
|
67ae21d18d | ||
|
|
db0acc854c | ||
|
|
1bbba50003 | ||
|
|
ec30ba9d02 | ||
|
|
2165e29c4f | ||
|
|
a8dfbc9147 | ||
|
|
3ea3cf7366 | ||
|
|
b6eeaa8cbc | ||
|
|
3e7ca3cddd | ||
|
|
f2363a8657 | ||
|
|
8de566f875 | ||
|
|
4f6d0999b7 | ||
|
|
2605382a79 | ||
|
|
29a989f09a | ||
|
|
9d9674d171 | ||
|
|
31d095e3cc | ||
|
|
51e2433404 | ||
|
|
20cd2064d4 | ||
|
|
8f97e9419f | ||
|
|
1a4b88829c | ||
|
|
42b4c56543 | ||
|
|
c9df104634 | ||
|
|
b89414a5d7 | ||
|
|
614fc27f03 | ||
|
|
79ac343eb2 | ||
|
|
35f03bf2e2 | ||
|
|
58d00d45b8 | ||
|
|
f3a4473162 | ||
|
|
554363e66f | ||
|
|
5d99323321 | ||
|
|
45de08dd39 | ||
|
|
40d6f1a19f | ||
|
|
fa5df75248 | ||
|
|
f9de245bc6 | ||
|
|
6bc625dd0c | ||
|
|
04b187923b | ||
|
|
807294e0eb | ||
|
|
a2a093836f | ||
|
|
5706e5e49d | ||
|
|
f3d876c5ef | ||
|
|
140255650d | ||
|
|
a81563768d | ||
|
|
83c54fbeac | ||
|
|
ed02a2b172 | ||
|
|
5f98f916a9 | ||
|
|
22ae57fc9b | ||
|
|
400b8fbef4 | ||
|
|
e4c8c47c2e | ||
|
|
f34035100c | ||
|
|
b8fc853cb8 | ||
|
|
6bcff00990 | ||
|
|
31c95c7ba2 | ||
|
|
29aa3e5eed | ||
|
|
1a9bad4e54 | ||
|
|
a4718a00b2 | ||
|
|
79012a6b08 | ||
|
|
18fe69d579 | ||
|
|
5c959e7274 | ||
|
|
803e7f1791 | ||
|
|
4b4351e3fa | ||
|
|
c9cbecc401 | ||
|
|
403e3c9f0e | ||
|
|
7feb3047e9 | ||
|
|
6e1550213c | ||
|
|
381e2d5b9a | ||
|
|
f93aefdbe5 | ||
|
|
d74ca31f68 | ||
|
|
a86c134377 | ||
|
|
84004349db | ||
|
|
8a257199a3 | ||
|
|
34916d7578 | ||
|
|
c2944b7fd8 | ||
|
|
4569547161 | ||
|
|
68bc6ee269 | ||
|
|
3da176fbfb | ||
|
|
3a8613b7ff | ||
|
|
facd1c0ce6 | ||
|
|
8ae999ecdf | ||
|
|
6ac3fdccdb | ||
|
|
841cc25a4e | ||
|
|
e365124af3 | ||
|
|
1696bb6d66 | ||
|
|
8c41065258 | ||
|
|
8fea101c8c | ||
|
|
2540205b77 | ||
|
|
4542f23143 | ||
|
|
c6185c3d9c | ||
|
|
163effc00d | ||
|
|
2d9a06a3fc | ||
|
|
cf82c409df | ||
|
|
db1ae5bfa2 | ||
|
|
8319cb2ad4 | ||
|
|
ab0f07bbd7 | ||
|
|
a59a68b6f5 | ||
|
|
78aa295876 | ||
|
|
8f6b539b37 | ||
|
|
9c7d1c5fe1 | ||
|
|
bb2dfe61dc | ||
|
|
a9d6242a43 | ||
|
|
7692899366 | ||
|
|
6befe661b7 | ||
|
|
f22191faa6 | ||
|
|
ca7552c9f6 | ||
|
|
fdc26c6b93 | ||
|
|
0bafc17994 | ||
|
|
15fd2ef8a0 | ||
|
|
d00c058c46 | ||
|
|
69183e2d79 | ||
|
|
96d0c432c7 | ||
|
|
97cdfbedaf | ||
|
|
ac19ece535 | ||
|
|
c954431442 | ||
|
|
36b3c9ff8f | ||
|
|
5847586121 | ||
|
|
c5ab28d75b | ||
|
|
52b210b016 | ||
|
|
8270d9035b | ||
|
|
8bbb9fc5f3 | ||
|
|
25ceed2703 | ||
|
|
7ed09f927d | ||
|
|
391d26cdc5 | ||
|
|
68e8536c89 | ||
|
|
a6b3163635 | ||
|
|
4860c08e03 | ||
|
|
cde78ea481 | ||
|
|
5be3300554 | ||
|
|
f53ae5e459 | ||
|
|
6c46705e98 | ||
|
|
455aa576e5 | ||
|
|
4a5f74b2d2 | ||
|
|
a55d3a5340 | ||
|
|
773a05e25c | ||
|
|
c4897ea0fb | ||
|
|
0963929a30 | ||
|
|
23b523b788 | ||
|
|
14a01c0e6d | ||
|
|
a03a3bdbf8 | ||
|
|
3610e87244 | ||
|
|
62420dade1 | ||
|
|
c7597dfcdf | ||
|
|
c4b52ef684 | ||
|
|
6f4617b83d | ||
|
|
4c332b7d16 | ||
|
|
7748d2bf03 | ||
|
|
881e94e8b0 | ||
|
|
72723d24f5 | ||
|
|
1ac08cfc2b | ||
|
|
79b9df3392 | ||
|
|
104c266bc0 | ||
|
|
fa31f4c5df | ||
|
|
31fa85f22e | ||
|
|
57563d4e40 | ||
|
|
6956631c61 | ||
|
|
16f1d3fcfb | ||
|
|
b20246b172 | ||
|
|
cff541b94b | ||
|
|
d44781fa1e | ||
|
|
ae002a6c17 | ||
|
|
11ea812897 | ||
|
|
73bca886b5 | ||
|
|
13b1fbe17a | ||
|
|
7e35fa2d56 | ||
|
|
fb0ec57f38 | ||
|
|
2ac2ff807f | ||
|
|
6f99ebed88 | ||
|
|
5bdbec273e | ||
|
|
0871b627ed | ||
|
|
2a84911862 | ||
|
|
bb67505613 | ||
|
|
efd98e6a6a | ||
|
|
d3d296b353 | ||
|
|
c89c7bd1ac | ||
|
|
857b798172 | ||
|
|
b4da713ac1 | ||
|
|
19ed0fdaf5 | ||
|
|
23d7b56c86 | ||
|
|
8b8552d54b | ||
|
|
28c3b35d39 | ||
|
|
58c5bb1d35 | ||
|
|
841be061e0 | ||
|
|
783bbfb4ba | ||
|
|
aea3b4758f | ||
|
|
92fcc116af | ||
|
|
dbd75615d9 | ||
|
|
1431cf8cde | ||
|
|
eb1806deaa | ||
|
|
23ffa73f4c | ||
| f4d676548f | |||
|
|
3e9a6256ad | ||
| 273ce0c186 | |||
|
|
e1e3e208cb | ||
|
|
f06f7e21c9 | ||
|
|
2a7067cd03 | ||
| 2c5f46f096 | |||
| 8aa52ba64a | |||
| c4d14847e8 | |||
|
|
026171e753 | ||
|
|
3a257aefb1 | ||
|
|
31bf7f45c4 | ||
|
|
5a6ede01d1 | ||
|
|
17d0c87c96 | ||
|
|
ea269686b5 | ||
|
|
4d5e6c6b59 | ||
|
|
9db1becebf | ||
|
|
57153dc8d2 | ||
|
|
52abebfc16 | ||
|
|
a634d046be | ||
| 3728c02b87 | |||
| ebdfb794ba | |||
| ac70331977 | |||
|
|
4b2b92c1ba | ||
|
|
38040bf9fd | ||
|
|
dc22d98322 | ||
|
|
131c951cb3 | ||
|
|
78edbe7f8d | ||
|
|
4e9072165b | ||
|
|
af040fb6ef | ||
|
|
8edb46afb4 | ||
|
|
e14d4e295a | ||
|
|
dfd64e7474 | ||
|
|
175c571fbb | ||
|
|
d21a9cffab | ||
|
|
26815fae74 | ||
|
|
6791c0c81e | ||
|
|
4ae8b5db3c | ||
|
|
eb6a4d9fd0 | ||
|
|
54f35ff396 | ||
|
|
b63ae3741d | ||
|
|
1f5e69972a | ||
|
|
a5cf3aa426 | ||
|
|
e7fe38cdf7 | ||
|
|
72215f1a05 | ||
|
|
563ae74a19 | ||
|
|
e765e9f9bd | ||
|
|
4d66290529 | ||
|
|
e299564b9c | ||
|
|
a8db1cc5e1 | ||
|
|
c4bb16e390 | ||
|
|
225f634f33 | ||
|
|
59afaf8263 | ||
|
|
0e25f34135 | ||
|
|
0ffacbbbe8 | ||
|
|
e50761364d | ||
|
|
2093f6f10f | ||
|
|
649fb3cd98 | ||
|
|
c98eb31a5e | ||
|
|
baa75999b6 | ||
|
|
5e5548809a | ||
|
|
a048bf385d | ||
|
|
e239c216b7 | ||
|
|
597abacc58 | ||
|
|
3bd794f2fb | ||
|
|
2d0db3dc71 | ||
|
|
eae3c69f85 | ||
|
|
e7e8b9141e | ||
|
|
444434efb6 | ||
|
|
0770c97f60 | ||
|
|
b236031554 | ||
|
|
00a5b4d5d3 | ||
| 33b110589d | |||
| 6649a5b987 | |||
| 5e38f7debd | |||
| 6220ab029b | |||
| 681b9d7dd0 | |||
| 7549f1b95a | |||
| a8ca70ca74 | |||
| d1763bdef1 | |||
| 6d938d30bf | |||
| 784980af93 | |||
| a47b52f086 | |||
| ed2e95b3f4 | |||
| 9390b0d638 | |||
| 21fdaeaa21 | |||
| 6e780173f9 | |||
| 3d90bd0392 | |||
| d25afcaeae | |||
| 637aedabc5 | |||
| c047eafa7e | |||
| 5e6226729a | |||
| 41562cf4c3 | |||
| f28b2f152e | |||
| 8458e49a30 | |||
|
|
3d72ca0cc6 | ||
|
|
6167cb4a43 | ||
| b2d5708fd8 | |||
| e455e36a39 | |||
| 73c9c5a228 | |||
| f4e9293643 | |||
| 249656039a | |||
| d871d91adb | |||
|
|
59537c9bd0 | ||
|
|
ead9d93f5b | ||
|
|
9b72ae7223 | ||
|
|
ca4ebf4ba7 | ||
|
|
e1c706b08f | ||
|
|
deec5edff9 | ||
|
|
f0d82a19ee | ||
|
|
0811f23b71 | ||
|
|
9d6f044d33 | ||
| bcf51c4535 | |||
|
|
3ae90fe9b1 | ||
| 031f189a4a | |||
|
|
2291ae5af3 | ||
|
|
1c9bd1836c | ||
|
|
874d3a0b88 | ||
|
|
2fd92764fd | ||
|
|
6a70f535b3 | ||
|
|
07e07831c3 | ||
|
|
f0ec979815 | ||
|
|
3e64b3b742 | ||
|
|
878db5a828 | ||
|
|
0312dbc829 | ||
|
|
3787a1da1d | ||
|
|
907a1b7713 | ||
|
|
ec366c15c6 | ||
|
|
4b687d36ff | ||
|
|
0946c67fe0 | ||
|
|
274cd58b49 | ||
|
|
157e64e0d8 | ||
|
|
6c055b91b9 | ||
|
|
a828551eb7 | ||
|
|
bfaf1f3689 | ||
|
|
5c486d1317 | ||
|
|
8bc4427c7c | ||
|
|
bd5cb80027 | ||
|
|
a53d6f1621 | ||
|
|
1c053af8d1 | ||
|
|
bec168ab53 | ||
|
|
8a049b06bd | ||
|
|
c2be07b9cc | ||
|
|
81c4853f04 | ||
|
|
783547a481 | ||
|
|
3dafa7573c | ||
|
|
60e1f77f8d | ||
|
|
f359d07a02 | ||
|
|
ca5881b6cc | ||
|
|
17805032da | ||
|
|
ae3a27c91d | ||
|
|
4268cff072 | ||
|
|
02d3512681 | ||
|
|
97d6f384f4 | ||
|
|
8b2b8ab83a | ||
|
|
dfd0d0532b | ||
|
|
5af32db45f | ||
|
|
35cb1fba24 | ||
|
|
b62bcb5a99 | ||
|
|
9da8b443ce | ||
|
|
c95c93499a | ||
|
|
428761ea22 | ||
|
|
82655d46c9 | ||
|
|
99de613655 | ||
|
|
bbe226b21f | ||
|
|
52a3c74e43 | ||
|
|
c0a855ab7a | ||
|
|
d1e6fdc948 | ||
|
|
be3d4ffaf9 | ||
|
|
1c82060daf | ||
|
|
0b404a51cb | ||
|
|
e4671902bb | ||
|
|
bed679d211 | ||
|
|
94fe68382f | ||
|
|
bb9c5c30df | ||
|
|
2ea64ce41f | ||
|
|
426993552c | ||
|
|
2b50aad4ef | ||
|
|
663ca1ccf0 | ||
|
|
189c4de298 | ||
|
|
d8e72e1466 | ||
|
|
ed3e7856e8 | ||
|
|
9b3e6bb177 | ||
|
|
b4a836873e | ||
|
|
62df3c9b5d | ||
|
|
e7aababa36 | ||
|
|
f3148ac206 | ||
|
|
7d3bb3480a | ||
|
|
7738142985 | ||
|
|
097a7fe94f | ||
|
|
2d39837f56 | ||
|
|
fe8d102748 | ||
|
|
10842207ea | ||
|
|
2dfb6ed07a | ||
|
|
9e4277e87f | ||
|
|
583f91399c | ||
|
|
e33816b64b | ||
|
|
8f94979e4c | ||
|
|
060e4b8c1f | ||
|
|
0cc3b77017 | ||
|
|
2d739cae19 | ||
|
|
67c86d7921 | ||
|
|
2cbda5d920 | ||
|
|
766bf5fa34 | ||
|
|
bd364d9967 | ||
|
|
2f96712371 | ||
|
|
6aa210159a | ||
|
|
8a5deb6ebb | ||
|
|
75343ccb23 | ||
|
|
589a1e7ae4 | ||
|
|
8ef573a800 | ||
|
|
fc84e657e3 | ||
|
|
197d8414bb | ||
|
|
a59592b799 | ||
|
|
ac82f6f33f | ||
|
|
2616c8378b | ||
|
|
6ec4353aef | ||
|
|
f50bbe5606 | ||
|
|
a73685553d | ||
|
|
eb7d63edd2 | ||
|
|
58cd2eb78c | ||
|
|
1e365ca72c | ||
|
|
17de5b3024 | ||
|
|
23bacf8b4d | ||
|
|
f9ed436d03 | ||
|
|
5d73dfc55d | ||
|
|
249aac934b | ||
|
|
fec9a3e621 | ||
|
|
afc0b8c58c | ||
|
|
bdece9e80c | ||
|
|
57b4595c11 | ||
|
|
51170e4a47 | ||
|
|
c157d85de6 | ||
|
|
c680da3154 | ||
|
|
360efc0805 | ||
|
|
0d4bab9098 | ||
|
|
bb94e595d1 | ||
|
|
8f34024833 | ||
|
|
1de9c1f639 | ||
|
|
2d77622476 | ||
|
|
4c15f278d0 | ||
|
|
70b536ea1b | ||
|
|
370e3e5e11 | ||
|
|
0da5644db5 | ||
|
|
d2410e12b1 | ||
|
|
23b3c07c51 | ||
|
|
e30a060344 | ||
|
|
9a5ff3440a | ||
|
|
52d7133e1b | ||
|
|
1132a6ecff | ||
|
|
70f2a92b9f | ||
|
|
30d968dea5 | ||
|
|
098dab4707 | ||
|
|
1b2fae94eb | ||
|
|
6099e62314 | ||
|
|
617ff4fc77 | ||
|
|
698566a8a7 | ||
|
|
8677538a29 | ||
|
|
ea8dd3f0e8 | ||
|
|
2868a955bb | ||
|
|
ff52c52349 | ||
|
|
4c2f475671 | ||
|
|
3edbe7cdf5 | ||
|
|
e88744eadc | ||
|
|
87453c80a7 | ||
|
|
7de1d4d55a | ||
|
|
a1f7a16ddc | ||
|
|
39ad3f2ef4 | ||
|
|
a8b92c0ff4 | ||
|
|
c416faf54d | ||
|
|
75d6b06509 | ||
|
|
e8830e6407 | ||
|
|
2081dcf979 | ||
|
|
3a475a78b3 | ||
|
|
9a085d1767 | ||
|
|
844813b787 | ||
|
|
1417dc37df | ||
|
|
4ba454f7a3 | ||
|
|
f1dc9486a5 | ||
|
|
79ae2cdc28 | ||
|
|
2d3abde352 | ||
|
|
ea3e64ec8c | ||
|
|
4bd4ab84dc | ||
|
|
16937c691c | ||
|
|
d7c38f95b5 | ||
|
|
8f114ad816 | ||
|
|
9a1a7f92b7 | ||
|
|
5e0e2c9c51 | ||
|
|
9864fb13cc | ||
|
|
f0f6a6a4fb | ||
|
|
d6b3091cc9 | ||
|
|
49379b177a | ||
|
|
39dd1a8e21 | ||
|
|
41aae44f21 | ||
|
|
fd8ff0cd84 | ||
|
|
d10ab9f70d | ||
|
|
236902c629 | ||
|
|
fb2c168a20 | ||
|
|
0c9e49a30d | ||
|
|
db725f8b5f | ||
|
|
6863f63a8f | ||
|
|
4909a7f61b | ||
|
|
e4cbb88e1d | ||
|
|
9affb3a214 | ||
|
|
689db5b032 | ||
|
|
7e06cc2e96 | ||
|
|
f44ba19be3 | ||
|
|
5b3231951f | ||
|
|
d3fd70a98d | ||
|
|
979364f274 | ||
|
|
b8a2ad9652 | ||
|
|
265ab42eb0 | ||
|
|
d33755538a | ||
|
|
87b3697e1c | ||
|
|
f03f4ebefd | ||
|
|
393952d800 | ||
|
|
1714195da4 | ||
|
|
0a31183e60 | ||
|
|
6485bf3576 | ||
|
|
e624034250 | ||
|
|
4e8b0ea9d5 | ||
|
|
7bfe8d4bbf | ||
|
|
8203ef465e | ||
|
|
acd81b6fae | ||
|
|
e19c2ccf96 | ||
|
|
a09def4ec3 | ||
|
|
f708fc4f98 | ||
|
|
7e2c4ea05f | ||
|
|
0aea2f277e | ||
|
|
de912bf92f | ||
|
|
a91400429b | ||
|
|
049a5fadee | ||
|
|
bf481b84dc | ||
|
|
47463290a6 | ||
|
|
cef275f900 | ||
|
|
529c23043c | ||
|
|
f5a4c37968 |
83
.clang-format
Normal file
83
.clang-format
Normal file
@ -0,0 +1,83 @@
|
||||
# clang-format configuration
|
||||
# compatible with clang-format 15
|
||||
|
||||
UseTab: Never
|
||||
ColumnLimit: 100
|
||||
|
||||
# Indent
|
||||
IndentWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentGotoLabels: true
|
||||
IndentRequiresClause: true
|
||||
IndentWrappedFunctionNames: true
|
||||
NamespaceIndentation: None
|
||||
LambdaBodyIndentation: Signature
|
||||
BitFieldColonSpacing: Both
|
||||
|
||||
# Insert
|
||||
InsertBraces: false
|
||||
|
||||
# Align
|
||||
AlignAfterOpenBracket: true
|
||||
|
||||
AlignArrayOfStructures: Left
|
||||
PointerAlignment: Left
|
||||
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterColon
|
||||
BreakStringLiterals: false
|
||||
CompactNamespaces: false
|
||||
Cpp11BracedListStyle: true
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: None
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
RequiresClausePosition: OwnLine
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
|
||||
# Space
|
||||
SeparateDefinitionBlocks: Always
|
||||
SpaceBeforeParens: Custom
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: false
|
||||
AfterForeachMacros: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: true
|
||||
AfterRequiresInClause: true
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: Never
|
||||
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
# Order
|
||||
QualifierAlignment: Custom
|
||||
QualifierOrder: ["constexpr", "const", "inline", "static", "type"]
|
||||
SortIncludes: Never
|
||||
IncludeBlocks: Merge
|
||||
|
||||
WhitespaceSensitiveMacros: ["PK_PROTECTED", "LUA_PROTECTED"]
|
||||
157
.github/workflows/main.yml
vendored
157
.github/workflows/main.yml
vendored
@ -1,157 +0,0 @@
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
jobs:
|
||||
build_win32_amalgamated:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Compile
|
||||
shell: powershell
|
||||
run: |
|
||||
python amalgamate.py
|
||||
cd amalgamated
|
||||
cl.exe /std:c++17 /EHsc /utf-8 /O2 /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: amalgamated/pkpy.exe
|
||||
build_win32:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Compile
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p output/windows/x86_64
|
||||
python cmake_build.py
|
||||
cp main.exe output/windows/x86_64
|
||||
cp pocketpy.dll output/windows/x86_64
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
- name: Unit Test
|
||||
run: python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
build_linux:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Clang
|
||||
uses: egor-tensin/setup-clang@v1
|
||||
with:
|
||||
version: 15
|
||||
platform: x64
|
||||
- name: Install libc++
|
||||
run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
|
||||
- name: Unit Test with Coverage
|
||||
run: bash run_tests.sh
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
directory: .coverage
|
||||
if: github.ref == 'refs/heads/main'
|
||||
- name: Compile
|
||||
run: |
|
||||
mkdir -p output/linux/x86_64
|
||||
python cmake_build.py
|
||||
cp main output/linux/x86_64
|
||||
cp libpocketpy.so output/linux/x86_64
|
||||
env:
|
||||
CXX: clang++
|
||||
CC: clang
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
- name: C Binding Test
|
||||
run: bash run_c_binding_test.sh
|
||||
build_linux_x86:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Alpine Linux for aarch64
|
||||
uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: x86
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3
|
||||
- name: Build and Test
|
||||
run: |
|
||||
uname -m
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
python scripts/run_tests.py benchmark
|
||||
shell: alpine.sh --root {0}
|
||||
build_darwin:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile and Test
|
||||
run: |
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
- run: |
|
||||
python amalgamate.py
|
||||
cd plugins/macos/pocketpy
|
||||
mkdir -p output/macos
|
||||
xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
|
||||
cp -r build/Release/pocketpy.bundle output/macos
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: plugins/macos/pocketpy/output
|
||||
build_android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23
|
||||
local-cache: false
|
||||
add-to-path: false
|
||||
- name: Compile Shared Library
|
||||
run: |
|
||||
bash build_android.sh arm64-v8a
|
||||
bash build_android.sh armeabi-v7a
|
||||
bash build_android.sh x86_64
|
||||
|
||||
mkdir -p output/android/arm64-v8a
|
||||
mkdir -p output/android/armeabi-v7a
|
||||
mkdir -p output/android/x86_64
|
||||
|
||||
cp build/android/arm64-v8a/libpocketpy.so output/android/arm64-v8a
|
||||
cp build/android/armeabi-v7a/libpocketpy.so output/android/armeabi-v7a
|
||||
cp build/android/x86_64/libpocketpy.so output/android/x86_64
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
build_ios:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile Frameworks
|
||||
run: |
|
||||
git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake
|
||||
bash build_ios.sh
|
||||
mkdir -p output/ios
|
||||
cp -r build/pocketpy.xcframework output/ios/pocketpy.xcframework
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
BIN
.github/workflows/main.zip
vendored
Normal file
BIN
.github/workflows/main.zip
vendored
Normal file
Binary file not shown.
3
.github/workflows/website.yml
vendored
3
.github/workflows/website.yml
vendored
@ -18,7 +18,6 @@ jobs:
|
||||
- uses: actions/setup-node@v3.1.1
|
||||
- name: Retype build
|
||||
run: |
|
||||
python scripts/build_references.py
|
||||
cd docs
|
||||
npm install retypeapp --global
|
||||
retype build
|
||||
@ -26,7 +25,7 @@ jobs:
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
with:
|
||||
version: 3.1.25
|
||||
version: latest
|
||||
actions-cache-folder: 'emsdk-cache'
|
||||
- name: Compile
|
||||
run: |
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -4,6 +4,7 @@ __pycache__/
|
||||
.DS_Store
|
||||
.coverage
|
||||
.idea
|
||||
.cache/clangd/
|
||||
|
||||
gmon.out
|
||||
gprof.txt
|
||||
@ -29,4 +30,7 @@ pocketpy.dSYM
|
||||
libpocketpy.dylib.dSYM/
|
||||
main.dSYM/
|
||||
|
||||
docs/references.md
|
||||
docs/references.md
|
||||
|
||||
.xmake
|
||||
.vs
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(cjson)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/../../include)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_library(
|
||||
cjson
|
||||
STATIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/cJSON.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/cJSONw.cpp
|
||||
)
|
||||
@ -1,10 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON 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 Sofware 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.
|
||||
|
||||
@ -1,300 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON 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 cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 16
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -1,8 +0,0 @@
|
||||
#include "cJSON.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_cjson(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,125 +0,0 @@
|
||||
#include "cJSONw.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
|
||||
static cJSON* convert_python_object_to_cjson(PyVar obj, VM* vm);
|
||||
static PyVar convert_cjson_to_python_object(const cJSON * const item, VM* vm);
|
||||
|
||||
template<typename T>
|
||||
static cJSON* convert_list_to_cjson(const T& list, VM* vm){
|
||||
cJSON *cjson_list = cJSON_CreateArray();
|
||||
for(auto& element : list){
|
||||
cJSON_AddItemToArray(cjson_list, convert_python_object_to_cjson(element, vm));
|
||||
}
|
||||
return cjson_list;
|
||||
}
|
||||
|
||||
static cJSON* covert_dict_to_cjson(const Dict& dict, VM* vm){
|
||||
cJSON *cjson_object = cJSON_CreateObject();
|
||||
dict.apply([&](PyVar key, PyVar val){
|
||||
cJSON_AddItemToObject(cjson_object, CAST(Str&, key).c_str(), convert_python_object_to_cjson(val, vm));
|
||||
});
|
||||
return cjson_object;
|
||||
}
|
||||
|
||||
static cJSON* convert_python_object_to_cjson(PyVar obj, VM* vm){
|
||||
if(obj == vm->None) return cJSON_CreateNull();
|
||||
Type obj_t = vm->_tp(obj);
|
||||
switch(obj_t){
|
||||
case VM::tp_int.index: cJSON_CreateNumber(_CAST(i64, obj));
|
||||
case VM::tp_float.index: cJSON_CreateNumber(_CAST(f64, obj));
|
||||
case VM::tp_bool.index: cJSON_CreateBool(obj == vm->True);
|
||||
case VM::tp_str.index: cJSON_CreateString(_CAST(Str&, obj).c_str());
|
||||
case VM::tp_dict.index: return covert_dict_to_cjson(_CAST(Dict&, obj), vm);
|
||||
case VM::tp_list.index: return convert_list_to_cjson<List>(_CAST(List&, obj), vm);
|
||||
case VM::tp_tuple.index: return convert_list_to_cjson<Tuple>(_CAST(Tuple&, obj), vm);
|
||||
default: break;
|
||||
}
|
||||
vm->TypeError(_S("unrecognized type ", _type_name(vm, obj_t).escape()));
|
||||
PK_UNREACHABLE()
|
||||
}
|
||||
|
||||
|
||||
static PyVar convert_cjson_to_list(const cJSON * const item, VM* vm){
|
||||
List output;
|
||||
cJSON *element = item->child;
|
||||
while(element != NULL){
|
||||
output.push_back(convert_cjson_to_python_object(element, vm));
|
||||
element = element->next;
|
||||
}
|
||||
return VAR(std::move(output));
|
||||
}
|
||||
|
||||
static PyVar convert_cjson_to_dict(const cJSON* const item, VM* vm){
|
||||
Dict output(vm);
|
||||
cJSON *child = item->child;
|
||||
while(child != NULL){
|
||||
const char* key = child->string;
|
||||
const cJSON *child_value = cJSON_GetObjectItemCaseSensitive(item, key);
|
||||
output.set(VAR(key), convert_cjson_to_python_object(child_value, vm));
|
||||
child = child->next;
|
||||
}
|
||||
return VAR(std::move(output));
|
||||
}
|
||||
|
||||
static PyVar convert_cjson_to_python_object(const cJSON * const item, VM* vm)
|
||||
{
|
||||
if (cJSON_IsString(item))
|
||||
{
|
||||
return VAR(Str(item->valuestring));
|
||||
}
|
||||
else if (cJSON_IsNumber(item)){
|
||||
if(item->valuedouble != item->valueint){
|
||||
return VAR(item->valuedouble);
|
||||
}
|
||||
return VAR(item->valueint);
|
||||
}
|
||||
else if (cJSON_IsBool(item)){
|
||||
return item->valueint!=0 ? vm->True : vm->False;
|
||||
}
|
||||
else if (cJSON_IsNull(item)){
|
||||
return vm->None;
|
||||
}
|
||||
else if (cJSON_IsArray(item)){
|
||||
return convert_cjson_to_list(item, vm);
|
||||
}
|
||||
else if (cJSON_IsObject(item)){
|
||||
return convert_cjson_to_dict(item, vm);
|
||||
}
|
||||
return vm->None;
|
||||
}
|
||||
|
||||
void add_module_cjson(VM* vm){
|
||||
PyVar mod = vm->new_module("cjson");
|
||||
|
||||
PK_LOCAL_STATIC cJSON_Hooks hooks;
|
||||
hooks.malloc_fn = pool64_alloc;
|
||||
hooks.free_fn = pool64_dealloc;
|
||||
cJSON_InitHooks(&hooks);
|
||||
|
||||
vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args){
|
||||
std::string_view sv;
|
||||
if(is_type(args[0], vm->tp_bytes)){
|
||||
sv = PK_OBJ_GET(Bytes, args[0]).sv();
|
||||
}else{
|
||||
sv = CAST(Str&, args[0]).sv();
|
||||
}
|
||||
cJSON *json = cJSON_ParseWithLength(sv.data(), sv.size());
|
||||
if(json == NULL){
|
||||
const char* start = cJSON_GetErrorPtr();
|
||||
const char* end = start;
|
||||
while(*end != '\0' && *end != '\n') end++;
|
||||
vm->IOError(_S("cjson: ", std::string_view(start, end-start)));
|
||||
}
|
||||
PyVar output = convert_cjson_to_python_object(json, vm);
|
||||
cJSON_Delete(json);
|
||||
return output;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) {
|
||||
return VAR(vm->py_json(args[0]));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy.h"
|
||||
|
||||
extern "C"{
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
void initialize_lua_bridge(VM* vm, lua_State* newL);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,346 +0,0 @@
|
||||
#include "lua_bridge.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
static lua_State* _L;
|
||||
static void lua_push_from_python(VM*, PyVar);
|
||||
static PyVar lua_popx_to_python(VM*);
|
||||
|
||||
template<typename T>
|
||||
static void table_apply(VM* vm, T f){
|
||||
PK_ASSERT(lua_istable(_L, -1));
|
||||
lua_pushnil(_L); // [key]
|
||||
while(lua_next(_L, -2) != 0){ // [key, val]
|
||||
lua_pushvalue(_L, -2); // [key, val, key]
|
||||
PyVar key = lua_popx_to_python(vm);
|
||||
PyVar val = lua_popx_to_python(vm);
|
||||
f(key, val); // [key]
|
||||
}
|
||||
lua_pop(_L, 1); // []
|
||||
}
|
||||
|
||||
struct LuaExceptionGuard{
|
||||
int base_size;
|
||||
LuaExceptionGuard(){ base_size = lua_gettop(_L); }
|
||||
~LuaExceptionGuard(){
|
||||
int delta = lua_gettop(_L) - base_size;
|
||||
if(delta > 0) lua_pop(_L, delta);
|
||||
}
|
||||
};
|
||||
|
||||
#define LUA_PROTECTED(__B) { LuaExceptionGuard __guard; __B; }
|
||||
|
||||
struct PyLuaObject{
|
||||
PK_ALWAYS_PASS_BY_POINTER(PyLuaObject)
|
||||
int r;
|
||||
PyLuaObject(){ r = luaL_ref(_L, LUA_REGISTRYINDEX); }
|
||||
~PyLuaObject(){ luaL_unref(_L, LUA_REGISTRYINDEX, r); }
|
||||
};
|
||||
|
||||
struct PyLuaTable: PyLuaObject{
|
||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
||||
Type t = PK_OBJ_GET(Type, type);
|
||||
PyTypeInfo* ti = &vm->_all_types[t];
|
||||
ti->subclass_enabled = false;
|
||||
ti->m__getattr__ = [](VM* vm, PyVar obj, StrName name){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
std::string_view name_sv = name.sv();
|
||||
lua_pushlstring(_L, name_sv.data(), name_sv.size());
|
||||
lua_gettable(_L, -2);
|
||||
PyVar ret = lua_popx_to_python(vm);
|
||||
lua_pop(_L, 1);
|
||||
return ret;
|
||||
)
|
||||
};
|
||||
|
||||
ti->m__setattr__ = [](VM* vm, PyVar obj, StrName name, PyVar val){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
std::string_view name_sv = name.sv();
|
||||
lua_pushlstring(_L, name_sv.data(), name_sv.size());
|
||||
lua_push_from_python(vm, val);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
};
|
||||
|
||||
ti->m__delattr__ = [](VM* vm, PyVar obj, StrName name){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
std::string_view name_sv = name.sv();
|
||||
lua_pushlstring(_L, name_sv.data(), name_sv.size());
|
||||
lua_pushnil(_L);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
return true;
|
||||
};
|
||||
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
|
||||
lua_newtable(_L); // push an empty table onto the stack
|
||||
PyVar obj = vm->heap.gcnew<PyLuaTable>(PK_OBJ_GET(Type, args[0]));
|
||||
return obj;
|
||||
});
|
||||
|
||||
vm->bind__len__(t, [](VM* vm, PyVar obj){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
i64 len = 0;
|
||||
lua_pushnil(_L);
|
||||
while(lua_next(_L, -2) != 0){ len += 1; lua_pop(_L, 1); }
|
||||
lua_pop(_L, 1);
|
||||
return len;
|
||||
});
|
||||
|
||||
vm->bind__getitem__(t, [](VM* vm, PyVar obj, PyVar key){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_gettable(_L, -2);
|
||||
PyVar ret = lua_popx_to_python(vm);
|
||||
lua_pop(_L, 1);
|
||||
return ret;
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind__setitem__(t, [](VM* vm, PyVar obj, PyVar key, PyVar val){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_push_from_python(vm, val);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind__delitem__(t, [](VM* vm, PyVar obj, PyVar key){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_pushnil(_L);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind__contains__(t, [](VM* vm, PyVar obj, PyVar key){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_gettable(_L, -2);
|
||||
bool ret = lua_isnil(_L, -1) == 0;
|
||||
lua_pop(_L, 2);
|
||||
return ret ? vm->True : vm->False;
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind(type, "keys(self) -> list", [](VM* vm, ArgsView args){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
List ret;
|
||||
table_apply(vm, [&](PyVar key, PyVar val){ ret.push_back(key); });
|
||||
lua_pop(_L, 1);
|
||||
return VAR(std::move(ret));
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind(type, "values(self) -> list", [](VM* vm, ArgsView args){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
List ret;
|
||||
table_apply(vm, [&](PyVar key, PyVar val){ ret.push_back(val); });
|
||||
lua_pop(_L, 1);
|
||||
return VAR(std::move(ret));
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind(type, "items(self) -> list[tuple]", [](VM* vm, ArgsView args){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
List ret;
|
||||
table_apply(vm, [&](PyVar key, PyVar val){
|
||||
PyVar item = VAR(Tuple(key, val));
|
||||
ret.push_back(item);
|
||||
});
|
||||
lua_pop(_L, 1);
|
||||
return VAR(std::move(ret));
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static PyVar lua_popx_multi_to_python(VM* vm, int count){
|
||||
if(count == 0){
|
||||
return vm->None;
|
||||
}else if(count == 1){
|
||||
return lua_popx_to_python(vm);
|
||||
}else if(count > 1){
|
||||
Tuple ret(count);
|
||||
for(int i=0; i<count; i++){
|
||||
ret[i] = lua_popx_to_python(vm);
|
||||
}
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
PK_FATAL_ERROR()
|
||||
}
|
||||
|
||||
struct PyLuaFunction: PyLuaObject{
|
||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
||||
vm->bind_func(type, __call__, -1, [](VM* vm, ArgsView args){
|
||||
if(args.size() < 1) vm->TypeError("__call__ takes at least 1 argument");
|
||||
const PyLuaFunction& self = _CAST(PyLuaFunction&, args[0]);
|
||||
int base_size = lua_gettop(_L);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
for(int i=1; i<args.size(); i++){
|
||||
lua_push_from_python(vm, args[i]);
|
||||
}
|
||||
if(lua_pcall(_L, args.size()-1, LUA_MULTRET, 0)){
|
||||
const char* error = lua_tostring(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
vm->RuntimeError(error);
|
||||
}
|
||||
return lua_popx_multi_to_python(vm, lua_gettop(_L) - base_size);
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void lua_push_from_python(VM* vm, PyVar val){
|
||||
if(val == vm->None){
|
||||
lua_pushnil(_L);
|
||||
return;
|
||||
}
|
||||
Type t = vm->_tp(val);
|
||||
switch(t.index){
|
||||
case VM::tp_bool.index:
|
||||
lua_pushboolean(_L, val == vm->True);
|
||||
return;
|
||||
case VM::tp_int.index:
|
||||
lua_pushinteger(_L, _CAST(i64, val));
|
||||
return;
|
||||
case VM::tp_float.index:
|
||||
lua_pushnumber(_L, _CAST(f64, val));
|
||||
return;
|
||||
case VM::tp_str.index: {
|
||||
std::string_view sv = _CAST(Str, val).sv();
|
||||
lua_pushlstring(_L, sv.data(), sv.size());
|
||||
return;
|
||||
}
|
||||
case VM::tp_tuple.index: {
|
||||
lua_newtable(_L);
|
||||
int i = 1;
|
||||
for(PyVar obj: PK_OBJ_GET(Tuple, val)){
|
||||
lua_push_from_python(vm, obj);
|
||||
lua_rawseti(_L, -2, i++);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VM::tp_list.index: {
|
||||
lua_newtable(_L);
|
||||
int i = 1;
|
||||
for(PyVar obj: PK_OBJ_GET(List, val)){
|
||||
lua_push_from_python(vm, obj);
|
||||
lua_rawseti(_L, -2, i++);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VM::tp_dict.index: {
|
||||
lua_newtable(_L);
|
||||
PK_OBJ_GET(Dict, val).apply([&](PyVar key, PyVar val){
|
||||
lua_push_from_python(vm, key);
|
||||
lua_push_from_python(vm, val);
|
||||
lua_settable(_L, -3);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(vm->is_user_type<PyLuaTable>(val)){
|
||||
const PyLuaTable& table = _CAST(PyLuaTable&, val);
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, table.r);
|
||||
return;
|
||||
}
|
||||
|
||||
if(vm->is_user_type<PyLuaFunction>(val)){
|
||||
const PyLuaFunction& func = _CAST(PyLuaFunction&, val);
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, func.r);
|
||||
return;
|
||||
}
|
||||
vm->RuntimeError(_S("unsupported python type: ", _type_name(vm, t).escape()));
|
||||
}
|
||||
|
||||
PyVar lua_popx_to_python(VM* vm) {
|
||||
int type = lua_type(_L, -1);
|
||||
switch (type) {
|
||||
case LUA_TNIL: {
|
||||
lua_pop(_L, 1);
|
||||
return vm->None;
|
||||
}
|
||||
case LUA_TBOOLEAN: {
|
||||
bool val = lua_toboolean(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
return val ? vm->True : vm->False;
|
||||
}
|
||||
case LUA_TNUMBER: {
|
||||
double val = lua_tonumber(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
return VAR(val);
|
||||
}
|
||||
case LUA_TSTRING: {
|
||||
const char* val = lua_tostring(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
return VAR(val);
|
||||
}
|
||||
case LUA_TTABLE: {
|
||||
PyVar obj = vm->new_user_object<PyLuaTable>();
|
||||
return obj;
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
PyVar obj = vm->new_user_object<PyLuaFunction>();
|
||||
return obj;
|
||||
}
|
||||
default: {
|
||||
const char* type_name = lua_typename(_L, type);
|
||||
lua_pop(_L, 1);
|
||||
vm->RuntimeError(_S("unsupported lua type: '", type_name, "'"));
|
||||
}
|
||||
}
|
||||
PK_UNREACHABLE()
|
||||
}
|
||||
|
||||
void initialize_lua_bridge(VM* vm, lua_State* newL){
|
||||
PyVar mod = vm->new_module("lua");
|
||||
|
||||
if(_L != nullptr){
|
||||
throw std::runtime_error("lua bridge already initialized");
|
||||
}
|
||||
_L = newL;
|
||||
|
||||
vm->register_user_class<PyLuaTable>(mod, "Table");
|
||||
vm->register_user_class<PyLuaFunction>(mod, "Function");
|
||||
|
||||
vm->bind(mod, "dostring(__source: str)", [](VM* vm, ArgsView args){
|
||||
const char* source = CAST(CString, args[0]);
|
||||
int base_size = lua_gettop(_L);
|
||||
if (luaL_dostring(_L, source)) {
|
||||
const char* error = lua_tostring(_L, -1);
|
||||
lua_pop(_L, 1); // pop error message from the stack
|
||||
vm->RuntimeError(error);
|
||||
}
|
||||
return lua_popx_multi_to_python(vm, lua_gettop(_L) - base_size);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
107
CMakeLists.txt
107
CMakeLists.txt
@ -2,27 +2,37 @@ cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(pocketpy)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /utf-8 /O2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /jumptablerdata /GS-")
|
||||
add_compile_options(/wd4267 /wd4244)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -frtti -O2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
endif()
|
||||
|
||||
# disable -Wshorten-64-to-32 for apple
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-shorten-64-to-32")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shorten-64-to-32")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src POCKETPY_SRC)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
file(GLOB_RECURSE POCKETPY_SRC ${CMAKE_CURRENT_LIST_DIR}/src/*.c)
|
||||
|
||||
option(PK_USE_CJSON "" OFF)
|
||||
if(PK_USE_CJSON)
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/3rd/cjson)
|
||||
add_definitions(-DPK_USE_CJSON)
|
||||
endif()
|
||||
# option(PK_USE_CJSON "" OFF)
|
||||
# if(PK_USE_CJSON)
|
||||
# add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/3rd/cjson)
|
||||
# add_definitions(-DPK_USE_CJSON)
|
||||
# endif()
|
||||
|
||||
option(PK_ENABLE_OS "" OFF)
|
||||
if(PK_ENABLE_OS)
|
||||
@ -34,21 +44,33 @@ if(PK_ENABLE_PROFILER)
|
||||
add_definitions(-DPK_ENABLE_PROFILER=1)
|
||||
endif()
|
||||
|
||||
option(PK_NO_EXPORT_C_API "" OFF)
|
||||
if(PK_NO_EXPORT_C_API)
|
||||
add_definitions(-DPK_NO_EXPORT_C_API)
|
||||
endif()
|
||||
|
||||
# PK_IS_MAIN determines whether the project is being used from root
|
||||
# or if it is added as a dependency (through add_subdirectory for example).
|
||||
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(PK_IS_MAIN TRUE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
||||
set(PK_IS_MAIN TRUE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
||||
|
||||
# @szdytom favored testing
|
||||
# disabled by default because @blueloveTH doesn't like it :C
|
||||
option(BUILD_TESTING "Build the testing tree." OFF)
|
||||
if (BUILD_TESTING)
|
||||
option(BUILD_TESTING_SANITIZE "Build the source with sanitizers" OFF)
|
||||
if (BUILD_TESTING_SANITIZE)
|
||||
if (MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /fno-omit-frame-pointer")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,leak,undefined")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(tests/)
|
||||
endif()
|
||||
else()
|
||||
set(PK_IS_MAIN FALSE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
set(PK_IS_MAIN FALSE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
endif()
|
||||
|
||||
if(PK_BUILD_SHARED_LIB)
|
||||
@ -56,43 +78,18 @@ if(PK_BUILD_SHARED_LIB)
|
||||
elseif(PK_BUILD_STATIC_LIB)
|
||||
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
||||
else()
|
||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||
set(PROJECT_EXE_NAME main)
|
||||
add_executable(${PROJECT_EXE_NAME} src2/main.cpp)
|
||||
add_executable(${PROJECT_EXE_NAME} src2/main.c)
|
||||
# static linked main
|
||||
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
||||
target_link_libraries(${PROJECT_EXE_NAME} ${PROJECT_NAME})
|
||||
target_link_libraries(${PROJECT_EXE_NAME} ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
if(PK_USE_CJSON)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE $<BUILD_INTERFACE:cjson>)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE cjson)
|
||||
endif()
|
||||
|
||||
option(PK_INSTALL "Generate the install target" OFF)
|
||||
if (PK_INSTALL)
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}_target
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING PATTERN "*.h"
|
||||
PATTERN "typings" EXCLUDE
|
||||
)
|
||||
|
||||
# generate config.cmake
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}_target
|
||||
FILE ${PROJECT_NAME}-config.cmake
|
||||
DESTINATION "share/${PROJECT_NAME}"
|
||||
)
|
||||
endif()
|
||||
# link math library
|
||||
if(UNIX)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE m)
|
||||
endif()
|
||||
107
README.md
107
README.md
@ -1,35 +1,45 @@
|
||||
# pocketpy: python interpreter in 1 file
|
||||
# pocketpy: portable python 3.x interpreter
|
||||
|
||||
<p>
|
||||
<a title="Build" href="https://github.com/pocketpy/pocketpy/actions/workflows" ><img src="https://github.com/pocketpy/pocketpy/actions/workflows/main.yml/badge.svg" /></a>
|
||||
<!-- Build -->
|
||||
<a title="Build" href="https://github.com/pocketpy/pocketpy/actions/workflows" >
|
||||
<img src="https://github.com/pocketpy/pocketpy/actions/workflows/main.yml/badge.svg" /></a>
|
||||
<!-- Codecov -->
|
||||
<a href="https://codecov.io/gh/pocketpy/pocketpy" >
|
||||
<img src="https://codecov.io/gh/pocketpy/pocketpy/branch/main/graph/badge.svg?token=TI9KAFL0RG"/>
|
||||
</a>
|
||||
<a href="https://en.wikipedia.org/wiki/C%2B%2B#Standardization">
|
||||
<img alt="C++17" src="https://img.shields.io/badge/C%2B%2B-17-blue.svg"></a>
|
||||
<img src="https://codecov.io/gh/pocketpy/pocketpy/branch/main/graph/badge.svg?token=TI9KAFL0RG"/></a>
|
||||
<!-- C11 -->
|
||||
<a href="https://en.wikipedia.org/wiki/C11_(C_standard_revision)">
|
||||
<img alt="Python" src="https://img.shields.io/badge/C-11-blue.svg"></a>
|
||||
<!-- License -->
|
||||
<a href="https://github.com/blueloveth/pocketpy/blob/main/LICENSE">
|
||||
<img alt="GitHub" src="https://img.shields.io/github/license/blueloveth/pocketpy.svg?color=blue"></a>
|
||||
<!-- Github Release -->
|
||||
<a href="https://github.com/blueloveth/pocketpy/releases">
|
||||
<img alt="GitHub release" src="https://img.shields.io/github/release/blueloveth/pocketpy.svg"></a>
|
||||
<!-- docs -->
|
||||
<a href="https://pocketpy.dev">
|
||||
<img alt="Website" src="https://img.shields.io/website/https/pocketpy.dev.svg?down_color=red&down_message=offline&up_color=blue&up_message=online"></a>
|
||||
<!-- Discord -->
|
||||
<a title="Discord" href="https://discord.gg/WWaq72GzXv" >
|
||||
<img src="https://img.shields.io/discord/1048978026131640390.svg" /></a>
|
||||
</p>
|
||||
|
||||
pkpy is a lightweight(~15K LOC) Python interpreter for game scripting, built on C++17 with STL.
|
||||
---
|
||||
## This branch is in alpha stage. Old implementation was moved to v1.x branch.
|
||||
---
|
||||
|
||||
pkpy is a lightweight(~15K LOC) Python 3.x interpreter for game scripting, written in C11.
|
||||
|
||||
It aims to be an alternative to lua for game scripting, with elegant syntax, powerful features and competitive performance.
|
||||
pkpy is extremely easy to embed via a single header file `pocketpy.h`, without external dependencies.
|
||||
|
||||
Please see https://pocketpy.dev for details and try the following resources.
|
||||
<!-- Please see https://pocketpy.dev for details and try the following resources.
|
||||
+ [Live Python Demo](https://pocketpy.dev/static/web/): Python REPL of the latest version
|
||||
+ [Live C++ Examples](https://pocketpy.github.io/examples/): Common usage of pkpy in C++
|
||||
+ [Live C++ Examples](https://pocketpy.github.io/examples/): Common usage of pkpy in C++ -->
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
pkpy should work on any platform with a C++17 compiler.
|
||||
pkpy should work on any platform with a C11 compiler.
|
||||
These platforms are officially tested.
|
||||
|
||||
+ Windows 64-bit
|
||||
@ -57,11 +67,6 @@ In your CMakelists.txt, add the following lines:
|
||||
```cmake
|
||||
add_subdirectory(pocketpy)
|
||||
target_link_libraries(<your_target> pocketpy)
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
# exceptions must be enabled for emscripten
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fexceptions")
|
||||
endif()
|
||||
```
|
||||
|
||||
See [CMakeLists.txt](https://github.com/pocketpy/pocketpy/blob/main/CMakeLists.txt) for details.
|
||||
@ -72,9 +77,7 @@ It is safe to use `main` branch in production if CI badge is green.
|
||||
|
||||
To compile it with your project, these flags must be set:
|
||||
|
||||
+ `--std=c++17` flag must be set
|
||||
+ RTTI must be enabled
|
||||
+ Exception must be enabled
|
||||
+ `--std=c11` flag must be set
|
||||
+ For MSVC, `/utf-8` flag must be set
|
||||
|
||||
For development build, use this snippet.
|
||||
@ -89,41 +92,63 @@ python scripts/run_tests.py
|
||||
|
||||
### Example
|
||||
|
||||
```cpp
|
||||
```c
|
||||
#include "pocketpy.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace pkpy;
|
||||
static bool int_add(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
py_i64 a = py_toint(py_arg(0));
|
||||
py_i64 b = py_toint(py_arg(1));
|
||||
py_newint(py_retval(), a + b);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(){
|
||||
// Create a virtual machine
|
||||
VM* vm = new VM();
|
||||
int main() {
|
||||
// Initialize pocketpy
|
||||
py_initialize();
|
||||
|
||||
// Hello world!
|
||||
vm->exec("print('Hello world!')");
|
||||
bool ok = py_exec("print('Hello world!')", "<string>", EXEC_MODE, NULL);
|
||||
if(!ok) goto __ERROR;
|
||||
|
||||
// Create a list
|
||||
vm->exec("a = [1, 2, 3]");
|
||||
// Create a list: [1, 2, 3]
|
||||
py_Ref r0 = py_getreg(0);
|
||||
py_newlistn(r0, 3);
|
||||
py_newint(py_list_getitem(r0, 0), 1);
|
||||
py_newint(py_list_getitem(r0, 1), 2);
|
||||
py_newint(py_list_getitem(r0, 2), 3);
|
||||
|
||||
// Eval the sum of the list
|
||||
PyVar result = vm->eval("sum(a)");
|
||||
std::cout << "Sum of the list: "<< py_cast<int>(vm, result) << std::endl; // 6
|
||||
py_Ref f_sum = py_getbuiltin(py_name("sum"));
|
||||
py_push(f_sum);
|
||||
py_pushnil();
|
||||
py_push(r0);
|
||||
ok = py_vectorcall(1, 0);
|
||||
if(!ok) goto __ERROR;
|
||||
|
||||
// Bindings
|
||||
vm->bind(vm->_main, "add(a: int, b: int)",
|
||||
[](VM* vm, ArgsView args){
|
||||
int a = py_cast<int>(vm, args[0]);
|
||||
int b = py_cast<int>(vm, args[1]);
|
||||
return py_var(vm, a + b);
|
||||
});
|
||||
printf("Sum of the list: %d\n", (int)py_toint(py_retval())); // 6
|
||||
|
||||
// Call the function
|
||||
PyVar f_add = vm->_main->attr("add");
|
||||
result = vm->call(f_add, py_var(vm, 3), py_var(vm, 7));
|
||||
std::cout << "Sum of 2 variables: "<< py_cast<int>(vm, result) << std::endl; // 10
|
||||
// Bind native `int_add` as a global variable
|
||||
py_newnativefunc(r0, int_add);
|
||||
py_setglobal(py_name("add"), r0);
|
||||
|
||||
// Dispose the virtual machine
|
||||
delete vm;
|
||||
// Call `add` in python
|
||||
ok = py_exec("add(3, 7)", "<string>", EVAL_MODE, NULL);
|
||||
if(!ok) goto __ERROR;
|
||||
|
||||
py_i64 res = py_toint(py_retval());
|
||||
printf("Sum of 2 variables: %d\n", (int)res); // 10
|
||||
|
||||
py_finalize();
|
||||
return 0;
|
||||
|
||||
__ERROR:
|
||||
py_printexc();
|
||||
py_finalize();
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
142
amalgamate.py
142
amalgamate.py
@ -1,78 +1,96 @@
|
||||
import os
|
||||
|
||||
assert os.system("python prebuild.py") == 0
|
||||
|
||||
with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f:
|
||||
OPCODES_TEXT = '\n' + f.read() + '\n'
|
||||
|
||||
pipeline = [
|
||||
["config.h", "export.h", "_generated.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "any.h"],
|
||||
["obj.h", "dict.h", "codeobject.h", "frame.h", "profiler.h"],
|
||||
["gc.h", "vm.h", "ceval.h", "lexer.h", "expr.h", "compiler.h", "repl.h"],
|
||||
["cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "array2d.h", "dataclasses.h", "random.h", "linalg.h", "easing.h", "io.h", "modules.h"],
|
||||
["pocketpy.h", "pocketpy_c.h"]
|
||||
]
|
||||
|
||||
copied = set()
|
||||
text = ""
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from typing import List, Dict
|
||||
|
||||
assert os.system("python prebuild.py") == 0
|
||||
|
||||
with open("include/pocketpy/xmacros/opcodes.h", "rt", encoding='utf-8') as f:
|
||||
OPCODES_TEXT = '\n' + f.read() + '\n'
|
||||
|
||||
class Header:
|
||||
path: str
|
||||
content: str # header+source (if exists)
|
||||
dependencies: List[str]
|
||||
|
||||
def __init__(self, path: str):
|
||||
self.path = path
|
||||
self.dependencies = []
|
||||
|
||||
# get raw content
|
||||
with open(f'include/pocketpy/{path}', 'rt', encoding='utf-8') as f:
|
||||
self.content = f.read()
|
||||
src_path = path.replace('.hpp', '.cpp').replace('.h', '.cpp')
|
||||
if os.path.exists(f'src/{src_path}'):
|
||||
with open(f'src/{src_path}', 'rt', encoding='utf-8') as f:
|
||||
self.content += f'\n\n/* {src_path} */\n\n'
|
||||
self.content += f.read()
|
||||
|
||||
# process raw content and get dependencies
|
||||
self.content = self.content.replace('#pragma once', '')
|
||||
def _replace(m):
|
||||
path = m.group(1)
|
||||
if path == 'opcodes.h':
|
||||
return OPCODES_TEXT
|
||||
if path != self.path:
|
||||
self.dependencies.append(path)
|
||||
return ''
|
||||
|
||||
self.content = re.sub(
|
||||
r'#include\s+"pocketpy/(.+)"\s*',
|
||||
_replace,
|
||||
self.content
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f'Header({self.path!r}, dependencies={self.dependencies})'
|
||||
|
||||
|
||||
headers: Dict[str, Header] = {}
|
||||
|
||||
for path in ['pocketpy.hpp', 'pocketpy_c.h']:
|
||||
headers[path] = Header(path)
|
||||
|
||||
directories = ['common', 'objects', 'interpreter', 'compiler', 'modules', 'tools']
|
||||
for directory in directories:
|
||||
files = os.listdir(f'include/pocketpy/{directory}')
|
||||
for file in sorted(files):
|
||||
assert file.endswith('.h') or file.endswith('.hpp')
|
||||
headers[f'{directory}/{file}'] = Header(f'{directory}/{file}')
|
||||
|
||||
text = '''#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 blueloveTH
|
||||
* Distributed Under The MIT License
|
||||
* https://github.com/pocketpy/pocketpy
|
||||
*/'''
|
||||
|
||||
while True:
|
||||
for h in headers.values():
|
||||
if not h.dependencies:
|
||||
break
|
||||
else:
|
||||
if headers:
|
||||
print(headers)
|
||||
raise Exception("Circular dependencies detected")
|
||||
break
|
||||
print(h.path)
|
||||
text += h.content
|
||||
del headers[h.path]
|
||||
for h2 in headers.values():
|
||||
h2.dependencies = [d for d in h2.dependencies if d != h.path]
|
||||
|
||||
if os.path.exists("amalgamated"):
|
||||
shutil.rmtree("amalgamated")
|
||||
time.sleep(0.5)
|
||||
os.mkdir("amalgamated")
|
||||
|
||||
def remove_copied_include(text):
|
||||
text = text.replace("#pragma once", "")
|
||||
|
||||
def _replace(m):
|
||||
key = m.group(1)
|
||||
if key.startswith("pocketpy/"):
|
||||
key = key[9:]
|
||||
if key in ["user_config.h", "cJSONw.hpp"]:
|
||||
return m.group(0)
|
||||
if "opcodes.h" in key:
|
||||
return OPCODES_TEXT
|
||||
assert key in copied, f"include {key} not found"
|
||||
return ""
|
||||
|
||||
text = re.sub(
|
||||
r'#include\s+"(.+)"\s*',
|
||||
_replace,
|
||||
text
|
||||
)
|
||||
return text
|
||||
|
||||
for seq in pipeline:
|
||||
for j in seq:
|
||||
print(j)
|
||||
with open("include/pocketpy/"+j, "rt", encoding='utf-8') as f:
|
||||
text += remove_copied_include(f.read()) + '\n'
|
||||
copied.add(j)
|
||||
j = j.replace(".h", ".cpp")
|
||||
if os.path.exists("src/"+j):
|
||||
with open("src/"+j, "rt", encoding='utf-8') as f:
|
||||
text += remove_copied_include(f.read()) + '\n'
|
||||
copied.add(j)
|
||||
|
||||
# use LF line endings instead of CRLF
|
||||
with open("amalgamated/pocketpy.h", "wt", encoding='utf-8', newline='\n') as f:
|
||||
final_text = \
|
||||
r'''/*
|
||||
* Copyright (c) 2024 blueloveTH
|
||||
* Distributed Under The MIT License
|
||||
* https://github.com/pocketpy/pocketpy
|
||||
*/
|
||||
|
||||
#ifndef POCKETPY_H
|
||||
#define POCKETPY_H
|
||||
''' + text + '\n#endif // POCKETPY_H'
|
||||
f.write(final_text)
|
||||
f.write(text)
|
||||
|
||||
shutil.copy("src2/main.cpp", "amalgamated/main.cpp")
|
||||
with open("amalgamated/main.cpp", "rt", encoding='utf-8') as f:
|
||||
|
||||
BIN
backup/vfs.zip
Normal file
BIN
backup/vfs.zip
Normal file
Binary file not shown.
20
benchmarks/dict_0.py
Normal file
20
benchmarks/dict_0.py
Normal file
@ -0,0 +1,20 @@
|
||||
# test basic get/set
|
||||
import random
|
||||
random.seed(7)
|
||||
|
||||
a = {str(i): i for i in range(100)}
|
||||
a['existed'] = 0
|
||||
a['missed'] = 0
|
||||
|
||||
for i in range(1000000):
|
||||
key = str(random.randint(-100, 100))
|
||||
if key in a:
|
||||
a['existed'] += 1
|
||||
else:
|
||||
a['missed'] += 1
|
||||
|
||||
existed = a['existed']
|
||||
missed = a['missed']
|
||||
|
||||
assert abs(existed - missed) < 10000
|
||||
|
||||
27
benchmarks/dict_1.py
Normal file
27
benchmarks/dict_1.py
Normal file
@ -0,0 +1,27 @@
|
||||
# test deletion
|
||||
rnd = 0
|
||||
keys = []
|
||||
while True:
|
||||
keys.append(rnd)
|
||||
rnd = ((rnd * 5) + 1) & 1023
|
||||
if rnd == 0:
|
||||
break
|
||||
|
||||
assert len(keys) == 1024
|
||||
|
||||
a = {k: k for k in keys}
|
||||
|
||||
for i in range(10000):
|
||||
if i % 2 == 0:
|
||||
# del all keys
|
||||
for k in keys:
|
||||
del a[k]
|
||||
assert len(a) == 0
|
||||
else:
|
||||
# add keys back
|
||||
for k in keys:
|
||||
a[k] = k
|
||||
assert len(a) == len(keys)
|
||||
|
||||
assert len(a) == len(keys)
|
||||
assert list(a.keys()) == keys # order matters
|
||||
@ -3,8 +3,4 @@ def fib(n):
|
||||
return n
|
||||
return fib(n-1) + fib(n-2)
|
||||
|
||||
assert fib(32) == 2178309
|
||||
|
||||
# from dis import dis
|
||||
# dis(fib)
|
||||
# 7049155 calls
|
||||
assert fib(36) == 14930352
|
||||
|
||||
3
benchmarks/loop_0_if.py
Normal file
3
benchmarks/loop_0_if.py
Normal file
@ -0,0 +1,3 @@
|
||||
for i in range(10000000):
|
||||
if i > 0:
|
||||
pass
|
||||
23
benchmarks/vec.py
Normal file
23
benchmarks/vec.py
Normal file
@ -0,0 +1,23 @@
|
||||
import sys
|
||||
|
||||
is_cpython = hasattr(sys, 'getrefcount')
|
||||
|
||||
if is_cpython:
|
||||
class vec2:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __add__(self, other):
|
||||
return vec2(self.x + other.x, self.y + other.y)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y
|
||||
else:
|
||||
from linalg import vec2
|
||||
|
||||
x = vec2(0, 0)
|
||||
for i in range(10000000):
|
||||
x += vec2(1, 1)
|
||||
|
||||
assert x == vec2(10000000, 10000000)
|
||||
18
build.sh
18
build.sh
@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if clang++ is installed
|
||||
if ! type -P clang++ >/dev/null 2>&1; then
|
||||
echo "clang++ is required and not installed. Kindly install it."
|
||||
echo "Run: sudo apt-get install libc++-dev libc++abi-dev clang"
|
||||
# Check if clang is installed
|
||||
if ! type -P clang >/dev/null 2>&1; then
|
||||
echo "clang is required and not installed. Kindly install it."
|
||||
echo "Run: sudo apt-get install clang"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -18,11 +18,11 @@ if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
SRC=$(find src/ -name "*.c")
|
||||
|
||||
echo "> Compiling and linking source files... "
|
||||
|
||||
FLAGS="-std=c++17 -O1 -stdlib=libc++ -frtti -Wfatal-errors -Iinclude"
|
||||
FLAGS="-std=c11 -O1 -Wfatal-errors -Iinclude -DNDEBUG"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
LIB_EXTENSION=".dylib"
|
||||
@ -33,12 +33,12 @@ else
|
||||
LINK_FLAGS="-Wl,-rpath=."
|
||||
fi
|
||||
|
||||
clang++ $FLAGS -o libpocketpy$LIB_EXTENSION $SRC -fPIC -shared
|
||||
clang $FLAGS -o libpocketpy$LIB_EXTENSION $SRC -fPIC -shared -lm
|
||||
|
||||
# compile main.cpp and link to libpocketpy.so
|
||||
echo "> Compiling main.cpp and linking to libpocketpy$LIB_EXTENSION..."
|
||||
echo "> Compiling main.c and linking to libpocketpy$LIB_EXTENSION..."
|
||||
|
||||
clang++ $FLAGS -o main -O1 src2/main.cpp -L. -lpocketpy $LINK_FLAGS
|
||||
clang $FLAGS -o main -O1 src2/main.c -L. -lpocketpy $LINK_FLAGS
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Build completed. Type \"./main\" to enter REPL."
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
set -e
|
||||
|
||||
# if no $1 default arm64-v8a
|
||||
if [ -z $1 ]; then
|
||||
$1=arm64-v8a
|
||||
@ -10,9 +12,8 @@ cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=$1 \
|
||||
-DANDROID_PLATFORM=android-22 \
|
||||
-DANDROID_STL=c++_shared \
|
||||
../../.. \
|
||||
-DPK_BUILD_SHARED_LIB=ON -DPK_USE_CJSON=ON \
|
||||
-DPK_BUILD_SHARED_LIB=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
cmake --build . --config Release
|
||||
|
||||
18
build_g.sh
18
build_g.sh
@ -1,5 +1,17 @@
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
set -e
|
||||
|
||||
FLAGS="-std=c++17 -O1 -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g"
|
||||
python prebuild.py
|
||||
|
||||
SRC=$(find src/ -name "*.c")
|
||||
|
||||
FLAGS="-std=c11 -lm -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1"
|
||||
|
||||
SANITIZE_FLAGS="-fsanitize=address,leak,undefined"
|
||||
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
SANITIZE_FLAGS="-fsanitize=address,undefined"
|
||||
fi
|
||||
|
||||
echo "Compiling C files..."
|
||||
clang $FLAGS $SANITIZE_FLAGS $SRC src2/main.c -o main
|
||||
|
||||
clang++ $FLAGS -o main -O1 src2/main.cpp $SRC
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
set -e
|
||||
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
11
build_web.sh
11
build_web.sh
@ -1,7 +1,14 @@
|
||||
set -e
|
||||
|
||||
python prebuild.py
|
||||
|
||||
rm -rf web/lib
|
||||
mkdir web/lib
|
||||
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
em++ $SRC -Iinclude/ -fexceptions -frtti -s -Os -sEXPORTED_FUNCTIONS=_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_vm -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js
|
||||
SRC=$(find src/ -name "*.c")
|
||||
|
||||
emcc $SRC -Iinclude/ -s -Os \
|
||||
-sEXPORTED_FUNCTIONS=_py_initialize,_py_exec,_py_finalize,_py_printexc,_py_clearexc \
|
||||
-sEXPORTED_RUNTIME_METHODS=ccall \
|
||||
-sALLOW_MEMORY_GROWTH=1 \
|
||||
-o web/lib/pocketpy.js
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
project(test_c_bindings)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_LIST_DIR}/../
|
||||
${CMAKE_CURRENT_LIST_DIR}/build/pocketpy/
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_LIST_DIR}/../include
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} test.c)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
pocketpy
|
||||
)
|
||||
@ -1,415 +0,0 @@
|
||||
#include "pocketpy_c.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//tests the c bindings for pocketpy
|
||||
|
||||
void check_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (!result) {
|
||||
printf("ERROR: failed where it should have succeed at line %i\n", lineno);
|
||||
if (!pkpy_clear_error(vm, NULL)) {
|
||||
printf("clear error reported everything was fine\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void fail_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (result) {
|
||||
printf("ERROR: succeeded where it should have failed line %i\n", lineno);
|
||||
exit(1);
|
||||
} else {
|
||||
char* message;
|
||||
if (pkpy_clear_error(vm, &message)) {
|
||||
printf("actually errored! line %i\n", lineno);
|
||||
free(message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void error_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (result) {
|
||||
printf("ERROR: succeeded where it should have failed line %i\n", lineno);
|
||||
exit(1);
|
||||
} else {
|
||||
char* message;
|
||||
if (!pkpy_clear_error(vm, &message)){
|
||||
printf("clear error reported everything was fine\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("successfully errored with this message: \n");
|
||||
printf("%s\n", message);
|
||||
free(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define check(r) check_impl(vm, (r), __LINE__)
|
||||
#define fail(r) fail_impl(vm, (r), __LINE__)
|
||||
#define error(r) error_impl(vm, (r), __LINE__)
|
||||
|
||||
int test_binding(pkpy_vm* vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_multiple_return(pkpy_vm* vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
pkpy_push_int(vm, 13);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int test_minus(pkpy_vm* vm) {
|
||||
int a, b;
|
||||
pkpy_to_int(vm, 0, &a);
|
||||
pkpy_to_int(vm, 1, &b);
|
||||
pkpy_push_int(vm, a - b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_fib(pkpy_vm* vm) {
|
||||
int n;
|
||||
pkpy_to_int(vm, 0, &n);
|
||||
if (n == 1) {
|
||||
pkpy_push_int(vm, n);
|
||||
} else {
|
||||
pkpy_getglobal(vm, pkpy_name("test_fib"));
|
||||
pkpy_push_null(vm);
|
||||
pkpy_push_int(vm, n-1);
|
||||
pkpy_vectorcall(vm, 1);
|
||||
int r_int;
|
||||
pkpy_to_int(vm, -1, &r_int);
|
||||
pkpy_pop_top(vm);
|
||||
pkpy_push_int(vm, r_int + n);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_default_argument(pkpy_vm* vm){
|
||||
int x;
|
||||
pkpy_to_int(vm, -1, &x);
|
||||
bool ok = x == 5;
|
||||
pkpy_push_bool(vm, ok);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_return_none(pkpy_vm* vm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_error_propagate(pkpy_vm* vm) {
|
||||
pkpy_error(vm, "NameError", pkpy_string("catch me"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_nested_error(pkpy_vm* vm) {
|
||||
pkpy_getglobal(vm, pkpy_name("error_from_python"));
|
||||
pkpy_push_null(vm);
|
||||
pkpy_vectorcall(vm, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PRINT_TITLE(x) printf("\n====== %s ======\n", x)
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
pkpy_vm* vm = pkpy_new_vm(true);
|
||||
|
||||
PRINT_TITLE("test basic exec");
|
||||
check(pkpy_exec(vm, "print('hello world!')"));
|
||||
fail(pkpy_getglobal(vm, pkpy_name("nonexistatn")));
|
||||
|
||||
// test int methods
|
||||
PRINT_TITLE("test int methods");
|
||||
int r_int;
|
||||
check(pkpy_push_int(vm, 11));
|
||||
pkpy_CName m_eleven = pkpy_name("eleven");
|
||||
check(pkpy_setglobal(vm, m_eleven));
|
||||
check(pkpy_exec(vm, "print(eleven)"));
|
||||
check(pkpy_getglobal(vm, m_eleven));
|
||||
check(pkpy_is_int(vm, -1));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("%i\n", r_int); // 11
|
||||
printf("%i\n", pkpy_stack_size(vm)); // 1
|
||||
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test float methods");
|
||||
double r_float;
|
||||
check(pkpy_push_float(vm, 11.125));
|
||||
pkpy_CName m_elevenf = pkpy_name("elevenf");
|
||||
check(pkpy_setglobal(vm, m_elevenf));
|
||||
check(pkpy_exec(vm, "print(elevenf)"));
|
||||
check(pkpy_getglobal(vm, m_elevenf));
|
||||
check(pkpy_is_float(vm, -1));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("%.3f\n", r_float);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test bool methods");
|
||||
bool r_bool;
|
||||
check(pkpy_push_bool(vm, false));
|
||||
pkpy_CName m_false_test = pkpy_name("false_test");
|
||||
check(pkpy_setglobal(vm, m_false_test));
|
||||
check(pkpy_exec(vm, "print(false_test)"));
|
||||
check(pkpy_getglobal(vm, m_false_test));
|
||||
check(pkpy_is_bool(vm, -1));
|
||||
check(pkpy_to_bool(vm, -1, &r_bool));
|
||||
printf("%i\n", r_bool);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test string methods");
|
||||
pkpy_CString r_string;
|
||||
check(pkpy_push_string(vm, pkpy_string("hello!")));
|
||||
check(pkpy_setglobal(vm, pkpy_name("hello1")));
|
||||
check(pkpy_exec(vm, "print(hello1)"));
|
||||
check(pkpy_push_string(vm, pkpy_string("hello!")));
|
||||
check(pkpy_is_string(vm, -1));
|
||||
check(pkpy_to_string(vm, -1, &r_string));
|
||||
|
||||
puts(r_string);
|
||||
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test none methods");
|
||||
check(pkpy_push_none(vm));
|
||||
pkpy_CName m_none = pkpy_name("none");
|
||||
check(pkpy_setglobal(vm, m_none));
|
||||
check(pkpy_exec(vm, "print(none)"));
|
||||
check(pkpy_getglobal(vm, m_none));
|
||||
check(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test voidp methods");
|
||||
void* vp = (void*) 123;
|
||||
check(pkpy_push_voidp(vm, vp));
|
||||
check(pkpy_setglobal(vm, pkpy_name("vp")));
|
||||
check(pkpy_exec(vm, "print(vp)"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("vp")));
|
||||
check(pkpy_is_voidp(vm, -1));
|
||||
vp = NULL;
|
||||
check(pkpy_to_voidp(vm, -1, &vp));
|
||||
printf("%i\n", (int) (intptr_t) vp);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
|
||||
PRINT_TITLE("test sizing and indexing");
|
||||
int stack_size = pkpy_stack_size(vm);
|
||||
printf("stack size %i\n", stack_size);
|
||||
check(pkpy_is_int(vm, 0));
|
||||
check(pkpy_is_float(vm, 1));
|
||||
check(pkpy_is_bool(vm, 2));
|
||||
check(pkpy_is_string(vm, 3));
|
||||
check(pkpy_is_none(vm, 4));
|
||||
check(pkpy_is_voidp(vm, 5));
|
||||
check(pkpy_is_int(vm, -6));
|
||||
check(pkpy_is_float(vm, -5));
|
||||
check(pkpy_is_bool(vm, -4));
|
||||
check(pkpy_is_string(vm, -3));
|
||||
check(pkpy_is_none(vm, -2));
|
||||
check(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test error catching");
|
||||
error(pkpy_exec(vm, "let's make sure syntax errors get caught"));
|
||||
//stack should be cleared after error is resolved
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test simple call");
|
||||
check(pkpy_exec(vm, "def x(x, y) : return x - y"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_vectorcall(vm, 2));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("x : %i\n", r_int);
|
||||
|
||||
PRINT_TITLE("test vararg call");
|
||||
check(pkpy_exec(vm, "def vararg_x(*x) : return sum(x)"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("vararg_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 1));
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_push_int(vm, 4));
|
||||
check(pkpy_push_int(vm, 5));
|
||||
check(pkpy_push_int(vm, 6));
|
||||
check(pkpy_vectorcall(vm, 6));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("vararg_x : %i\n", r_int);
|
||||
|
||||
PRINT_TITLE("test keyword call");
|
||||
check(pkpy_exec(vm, "def keyword_x(x=1, y=1) : return x+y"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("keyword_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_vectorcall(vm, 1));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("keyword_x : %i\n", r_int); // 3+1
|
||||
|
||||
check(pkpy_getglobal(vm, pkpy_name("keyword_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("keyword_x : %i\n", r_int); // 1+1
|
||||
check(pkpy_stack_size(vm) == 4);
|
||||
check(pkpy_pop(vm, 4)); // clear stack
|
||||
|
||||
PRINT_TITLE("test return many");
|
||||
check(pkpy_exec(vm, "def retmany_x() : return 1, 2, 3"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("retmany_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
|
||||
check(pkpy_stack_size(vm) == 1);
|
||||
check(pkpy_unpack_sequence(vm, 3));
|
||||
check(pkpy_stack_size(vm) == 3);
|
||||
|
||||
check(pkpy_to_int(vm, -3, &r_int));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
check(pkpy_to_int(vm, -2, &r_int));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
|
||||
// test argument error
|
||||
check(pkpy_getglobal(vm, pkpy_name("x")));
|
||||
check(pkpy_push_null(vm));
|
||||
error(pkpy_vectorcall(vm, 0));
|
||||
|
||||
check(pkpy_exec(vm, "l = []"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("l")));
|
||||
check(pkpy_get_unbound_method(vm, pkpy_name("append")));
|
||||
check(pkpy_push_string(vm, pkpy_string("hello")));
|
||||
check(pkpy_vectorcall(vm, 1));
|
||||
check(pkpy_pop_top(vm)); // pop None returned by append()
|
||||
check(pkpy_exec(vm, "print(l)"));
|
||||
|
||||
PRINT_TITLE("test bindings");
|
||||
check(pkpy_push_function(vm, "test_binding()", test_binding));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_binding")));
|
||||
check(pkpy_exec(vm, "print(test_binding())"));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
check(pkpy_push_function(vm, "test_multiple_return()", test_multiple_return));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_multiple_return")));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
check(pkpy_push_function(vm, "test_default_argument(x=5)", test_default_argument));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
check(pkpy_stack_size(vm) == 1);
|
||||
check(pkpy_is_bool(vm, -1) == true);
|
||||
check(pkpy_to_bool(vm, -1, &r_bool));
|
||||
check(r_bool == true);
|
||||
check(pkpy_pop_top(vm));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test bindings 2");
|
||||
check(pkpy_push_function(vm, "test_minus(a, b)", test_minus));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_minus")));
|
||||
check(pkpy_exec(vm, "print(test_minus(5, 3))"));
|
||||
check(pkpy_exec(vm, "for i in range(5): print(test_minus(5, i))"));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test bindings fib");
|
||||
check(pkpy_push_function(vm, "test_fib(n: int) -> int", test_fib));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_fib")));
|
||||
check(pkpy_exec(vm, "print(test_fib(10))"));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test error propagate");
|
||||
check(pkpy_push_function(vm, "test_error_propagate()", test_error_propagate));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_error_propagate")));
|
||||
error(pkpy_exec(vm, "test_error_propagate()"));
|
||||
|
||||
check(pkpy_getglobal(vm, pkpy_name("test_multiple_return")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
check(pkpy_stack_size(vm) == 1);
|
||||
check(pkpy_unpack_sequence(vm, 2));
|
||||
check(pkpy_stack_size(vm) == 2);
|
||||
check(pkpy_pop(vm, 2));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test other errors");
|
||||
check(pkpy_getglobal(vm, pkpy_name("test_error_propagate")));
|
||||
check(pkpy_pop_top(vm));
|
||||
fail(pkpy_getglobal(vm, pkpy_name("nonexistant")));
|
||||
error(pkpy_exec(vm, "raise NameError('testing error throwing from python')"));
|
||||
|
||||
PRINT_TITLE("test TypeError");
|
||||
check(pkpy_push_float(vm, 2.0));
|
||||
error(pkpy_to_int(vm, -1, &r_int));
|
||||
|
||||
PRINT_TITLE("test complicated errors");
|
||||
pkpy_exec(vm, "test_error_propagate()");
|
||||
check(pkpy_check_error(vm));
|
||||
pkpy_clear_error(vm, NULL);
|
||||
|
||||
//this should be catchable
|
||||
check(pkpy_exec(vm, "try :\n test_error_propagate()\nexcept NameError : pass"));
|
||||
error(pkpy_error(vm, "Exception", pkpy_string("test direct error mechanism")));
|
||||
|
||||
//more complicated error handling
|
||||
check(pkpy_exec(vm, "def error_from_python() : raise NotImplementedError()"));
|
||||
check(pkpy_push_function(vm, "test_nested_error()", test_nested_error));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_nested_error")));
|
||||
error(pkpy_exec(vm, "test_nested_error()"));
|
||||
|
||||
PRINT_TITLE("test getattr/setattr");
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
check(pkpy_exec(vm, "import math"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("math")));
|
||||
check(pkpy_getattr(vm, pkpy_name("pi")));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("pi: %.2f\n", (float)r_float);
|
||||
check(pkpy_pop(vm, 1));
|
||||
|
||||
// math.pi = 2
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_eval(vm, "math"));
|
||||
check(pkpy_setattr(vm, pkpy_name("pi")));
|
||||
check(pkpy_exec(vm, "print(math.pi)"));
|
||||
|
||||
PRINT_TITLE("test eval");
|
||||
check(pkpy_eval(vm, "math.pi"));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("pi: %.2f\n", (float)r_float);
|
||||
check(pkpy_pop(vm, 1));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test py_repr");
|
||||
check(pkpy_eval(vm, "['1', 2, (3, '4')]"));
|
||||
check(pkpy_py_repr(vm));
|
||||
check(pkpy_to_string(vm, -1, &r_string));
|
||||
|
||||
puts(r_string);
|
||||
check(pkpy_pop_top(vm));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
return 0;
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
|
||||
====== test basic exec ======
|
||||
hello world!
|
||||
|
||||
====== test int methods ======
|
||||
11
|
||||
11
|
||||
1
|
||||
|
||||
====== test float methods ======
|
||||
11.125
|
||||
11.125
|
||||
|
||||
====== test bool methods ======
|
||||
False
|
||||
0
|
||||
|
||||
====== test string methods ======
|
||||
hello!
|
||||
hello!
|
||||
|
||||
====== test none methods ======
|
||||
None
|
||||
|
||||
====== test voidp methods ======
|
||||
<void* at 0x7b>
|
||||
123
|
||||
|
||||
====== test sizing and indexing ======
|
||||
stack size 6
|
||||
|
||||
====== test error catching ======
|
||||
successfully errored with this message:
|
||||
File "main.py", line 1
|
||||
let's make sure syntax errors get caught
|
||||
SyntaxError: EOL while scanning string literal
|
||||
|
||||
====== test simple call ======
|
||||
x : -1
|
||||
|
||||
====== test vararg call ======
|
||||
vararg_x : 21
|
||||
|
||||
====== test keyword call ======
|
||||
keyword_x : 4
|
||||
keyword_x : 2
|
||||
|
||||
====== test return many ======
|
||||
retmany_x : 1
|
||||
retmany_x : 2
|
||||
retmany_x : 3
|
||||
successfully errored with this message:
|
||||
TypeError: x() takes 2 positional arguments but 0 were given
|
||||
['hello']
|
||||
|
||||
====== test bindings ======
|
||||
12
|
||||
|
||||
====== test bindings 2 ======
|
||||
2
|
||||
5
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
|
||||
====== test bindings fib ======
|
||||
55
|
||||
|
||||
====== test error propagate ======
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_error_propagate()
|
||||
NameError: catch me
|
||||
|
||||
====== test other errors ======
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
raise NameError('testing error throwing from python')
|
||||
NameError: testing error throwing from python
|
||||
|
||||
====== test TypeError ======
|
||||
successfully errored with this message:
|
||||
TypeError: expected 'int', got 'float'
|
||||
|
||||
====== test complicated errors ======
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_error_propagate()
|
||||
NameError: catch me
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
Exception: test direct error mechanism
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_nested_error()
|
||||
File "main.py", line 1, in error_from_python
|
||||
def error_from_python() : raise NotImplementedError()
|
||||
NotImplementedError
|
||||
|
||||
====== test getattr/setattr ======
|
||||
pi: 3.14
|
||||
2
|
||||
|
||||
====== test eval ======
|
||||
pi: 2.00
|
||||
|
||||
====== test py_repr ======
|
||||
['1', 2, (3, '4')]
|
||||
@ -7,21 +7,28 @@ assert os.system("python prebuild.py") == 0
|
||||
if not os.path.exists("build"):
|
||||
os.mkdir("build")
|
||||
|
||||
config = 'Release'
|
||||
assert len(sys.argv) <= 2
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
config = sys.argv[1]
|
||||
else:
|
||||
config = 'Release'
|
||||
|
||||
assert config in ['Debug', 'Release', 'RelWithDebInfo']
|
||||
|
||||
os.chdir("build")
|
||||
|
||||
code = os.system(f"cmake .. -DPK_USE_CJSON=ON -DPK_ENABLE_OS=ON -DCMAKE_BUILD_TYPE={config}")
|
||||
code = os.system(f"cmake .. -DPK_ENABLE_OS=ON -DCMAKE_BUILD_TYPE={config}")
|
||||
assert code == 0
|
||||
code = os.system(f"cmake --build . --config {config}")
|
||||
assert code == 0
|
||||
|
||||
if sys.platform == "win32":
|
||||
shutil.copy(f"{config}/main.exe", "../main.exe")
|
||||
shutil.copy(f"{config}/pocketpy.dll", "../pocketpy.dll")
|
||||
# shutil.copy(f"{config}/pocketpy.dll", "../pocketpy.dll")
|
||||
elif sys.platform == "darwin":
|
||||
shutil.copy("main", "../main")
|
||||
shutil.copy("libpocketpy.dylib", "../libpocketpy.dylib")
|
||||
# shutil.copy("libpocketpy.dylib", "../libpocketpy.dylib")
|
||||
else:
|
||||
shutil.copy("main", "../main")
|
||||
shutil.copy("libpocketpy.so", "../libpocketpy.so")
|
||||
# shutil.copy("libpocketpy.so", "../libpocketpy.so")
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
-xc++
|
||||
|
||||
-Wall
|
||||
-W*
|
||||
|
||||
-std=c++17
|
||||
-stdlib=libc++
|
||||
|
||||
-xc
|
||||
-std=c11
|
||||
-Iinclude/
|
||||
-I3rd/cjson/include/
|
||||
-I3rd/lua_bridge/include/
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
icon: log
|
||||
title: 'Upgrade to v1.5.0'
|
||||
title: 'Upgrade to v2.0.0'
|
||||
order: 25
|
||||
---
|
||||
|
||||
@ -46,14 +46,14 @@ struct Point{
|
||||
|
||||
int x, y;
|
||||
|
||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
// do bindings here
|
||||
}
|
||||
};
|
||||
|
||||
int main(){
|
||||
VM* vm = new VM();
|
||||
PyVar mod = vm->new_module("test");
|
||||
PyObject* mod = vm->new_module("test");
|
||||
Point::register_class(vm, mod);
|
||||
return 0;
|
||||
}
|
||||
@ -68,7 +68,7 @@ struct Point{
|
||||
|
||||
int main(){
|
||||
VM* vm = new VM();
|
||||
PyVar mod = vm->new_module("test");
|
||||
PyObject* mod = vm->new_module("test");
|
||||
vm->register_user_class<Point>(mod, "Point",
|
||||
[](VM* vm, PyVar mod, PyVar type){
|
||||
// do bindings here
|
||||
@ -84,14 +84,14 @@ This is achieved by an overloaded version of `vm->register_user_class<>`. For ex
|
||||
struct Point{
|
||||
int x, y;
|
||||
|
||||
static void _register(VM* vm, PyVar mod, PyVar type){
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
// do bindings here (if you like the intrusive way)
|
||||
}
|
||||
};
|
||||
|
||||
int main(){
|
||||
VM* vm = new VM();
|
||||
PyVar mod = vm->new_module("test");
|
||||
PyObject* mod = vm->new_module("test");
|
||||
vm->register_user_class<Point>(mod, "Point");
|
||||
return 0;
|
||||
}
|
||||
@ -184,7 +184,7 @@ Please use config macros before `#include "pocketpy.h"` directly.
|
||||
#define PK_ENABLE_OS 1
|
||||
#define PK_ENABLE_THREAD 1
|
||||
#define PK_ENABLE_PROFILER 1
|
||||
// for all config macros, please refer to `include/pocketpy/config.h`
|
||||
// for all config macros, please refer to `include/pocketpy/common/config.h`
|
||||
#include "pocketpy.h"
|
||||
```
|
||||
|
||||
@ -207,7 +207,7 @@ Enabling the profiler has a performance overhead. Only enable it when you need i
|
||||
+ `vm->is_non_tagged_type` was removed. Use `vm->is_type` instead.
|
||||
+ `vm->check_non_tagged_type` was removed. Use `vm->check_type` instead.
|
||||
|
||||
## Python Stringify functions
|
||||
## Python stringify functions
|
||||
|
||||
The following functions now return `Str` object instead of `PyVar`:
|
||||
|
||||
@ -216,3 +216,7 @@ The following functions now return `Str` object instead of `PyVar`:
|
||||
+ `vm->py_json`
|
||||
|
||||
Also, `vm->bind__str__` and `vm->bind__repr__` were changed to return `Str` object.
|
||||
|
||||
## Catching exceptions
|
||||
|
||||
Now you need to catch `TopLevelException` instead of `Exception`.
|
||||
@ -150,4 +150,20 @@ PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||
|
||||
```
|
||||
[value] -> [repr(value)]
|
||||
```
|
||||
```
|
||||
|
||||
+ `bool pkpy_py_str(pkpy_vm*)`
|
||||
|
||||
Get the str of the value at the top of the stack.
|
||||
|
||||
```
|
||||
[value] -> [str(value)]
|
||||
```
|
||||
|
||||
+ `bool pkpy_py_import(pkpy_vm*, const char* name)`
|
||||
|
||||
Import a module and push it onto the stack.
|
||||
|
||||
```
|
||||
[] -> [module]
|
||||
```
|
||||
|
||||
@ -92,13 +92,6 @@ vm->bind(obj, "f() -> int", [](VM* vm, ArgsView args){
|
||||
}, x); // capture x
|
||||
```
|
||||
|
||||
The 3rd way is to change the macro `PK_ENABLE_STD_FUNCTION` in `config.h`:
|
||||
```cpp
|
||||
#define PK_ENABLE_STD_FUNCTION 0 // => 1
|
||||
```
|
||||
|
||||
Then you can use standard capture list in lambda.
|
||||
|
||||
## Bind a class or struct
|
||||
|
||||
Assume you have a struct `Point` declared as follows.
|
||||
@ -115,7 +108,7 @@ You can create a `test` module and use `vm->register_user_class<>` to bind the c
|
||||
```cpp
|
||||
int main(){
|
||||
VM* vm = new VM();
|
||||
PyVar mod = vm->new_module("test");
|
||||
PyObject* mod = vm->new_module("test");
|
||||
vm->register_user_class<Point>(mod, "Point",
|
||||
[](VM* vm, PyVar mod, PyVar type){
|
||||
// wrap field x
|
||||
@ -155,7 +148,7 @@ struct Container{
|
||||
}
|
||||
```
|
||||
|
||||
Add a magic method `_gc_mark() const` to your custom type.
|
||||
Add a magic method `_gc_mark(VM*) const` to your custom type.
|
||||
|
||||
```cpp
|
||||
struct Container{
|
||||
@ -163,13 +156,13 @@ struct Container{
|
||||
std::vector<PyVar> b;
|
||||
// ...
|
||||
|
||||
void _gc_mark() const{
|
||||
void _gc_mark(VM* vm) const{
|
||||
// mark a
|
||||
if(a) PK_OBJ_MARK(a);
|
||||
vm->obj_gc_mark(a);
|
||||
|
||||
// mark elements in b
|
||||
for(PyVar obj : b){
|
||||
if(obj) PK_OBJ_MARK(obj);
|
||||
vm->obj_gc_mark(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ Execute a compiled code object
|
||||
```cpp
|
||||
try{
|
||||
vm->_exec(co); // may throw
|
||||
}catch(Exception& e){
|
||||
}catch(TopLevelException e){
|
||||
std::cerr << e.summary() << std::endl;
|
||||
}
|
||||
```
|
||||
@ -328,6 +328,6 @@ vm->_lazy_modules["test"] = "pi = 3.14";
|
||||
Create a native module
|
||||
|
||||
```cpp
|
||||
PyVar mod = vm->new_module("test");
|
||||
PyObject* mod = vm->new_module("test");
|
||||
vm->setattr(mod, "pi", py_var(vm, 3.14));
|
||||
```
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Increment Statement
|
||||
---
|
||||
|
||||
pkpy provides `++i` and `--j` statements to operate a simple named `int` variable.
|
||||
|
||||
+ `++i` is equivalent to `i+=1`, but much faster
|
||||
+ `--j` is equivalent to `j-=1`, but much faster
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
a = 1
|
||||
++a
|
||||
assert a == 2
|
||||
|
||||
def f(a):
|
||||
--a
|
||||
return a
|
||||
|
||||
assert f(3) == 2
|
||||
```
|
||||
@ -13,7 +13,7 @@ https://github.com/pocketpy/pocketpy/blob/main/include/typings/linalg.pyi
|
||||
from typing import overload
|
||||
from c import _StructLike, float_p
|
||||
|
||||
class vec2(_StructLike['vec2']):
|
||||
class vec2:
|
||||
x: float
|
||||
y: float
|
||||
|
||||
@ -36,10 +36,6 @@ class vec2(_StructLike['vec2']):
|
||||
def normalize(self) -> vec2: ...
|
||||
def rotate(self, radians: float) -> vec2: ...
|
||||
|
||||
def copy_(self, other: vec2) -> None: ...
|
||||
def normalize_(self) -> None: ...
|
||||
def rotate_(self, radians: float) -> None: ...
|
||||
|
||||
@staticmethod
|
||||
def angle(__from: vec2, __to: vec2) -> float:
|
||||
"""Returns the angle in radians between vectors `from` and `to`.
|
||||
@ -51,10 +47,10 @@ class vec2(_StructLike['vec2']):
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2:
|
||||
def smooth_damp(current: vec2, target: vec2, current_velocity: vec2, smooth_time: float, max_speed: float, delta_time: float) -> tuple[vec2, vec2]:
|
||||
...
|
||||
|
||||
class vec3(_StructLike['vec3']):
|
||||
class vec3:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
@ -77,9 +73,6 @@ class vec3(_StructLike['vec3']):
|
||||
def length_squared(self) -> float: ...
|
||||
def normalize(self) -> vec3: ...
|
||||
|
||||
def copy_(self, other: vec3) -> None: ...
|
||||
def normalize_(self) -> None: ...
|
||||
|
||||
class vec4(_StructLike['vec4']):
|
||||
x: float
|
||||
y: float
|
||||
@ -175,8 +168,6 @@ class mat3x3(_StructLike['mat3x3']):
|
||||
def inverse_transform_point(self, p: vec2) -> vec2: ...
|
||||
def inverse_transform_vector(self, v: vec2) -> vec2: ...
|
||||
|
||||
vec2_p = float_p
|
||||
vec3_p = float_p
|
||||
vec4_p = float_p
|
||||
mat3x3_p = float_p
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ These two methods are provided for this purpose:
|
||||
try{
|
||||
CodeObject_ code = vm->compile("a[0]", "main.py", EXEC_MODE, false);
|
||||
vm->_exec(code, vm->_main);
|
||||
}catch(Exception& e){
|
||||
}catch(TopLevelException e){
|
||||
// use e.summary() to get a summary of the exception
|
||||
std::cerr << e.summary() << std::endl;
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ order: 0
|
||||
Sometimes you need to use the following code to prevent the gc from collecting objects.
|
||||
|
||||
```cpp
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
auto _lock = vm->gc_scope_lock();
|
||||
```
|
||||
|
||||
The scope lock is required if you create a PyVar and then try to run python-level bytecodes.
|
||||
@ -34,7 +34,7 @@ The scope lock prevents this from happening.
|
||||
void some_func(VM* vm){
|
||||
PyVar obj = VAR(List(5));
|
||||
// safe
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
auto _lock = vm->gc_scope_lock();
|
||||
PyVar iter = vm->py_iter(obj);
|
||||
PyVar next = vm->py_next(iter);
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ Native modules are always compiled and executed when the VM is created.
|
||||
To creata a native module, use `vm->new_module(Str name)`.
|
||||
|
||||
```cpp
|
||||
PyVar mod = vm->new_module("test");
|
||||
PyObject* mod = vm->new_module("test");
|
||||
mod->attr().set("pi", py_var(vm, 3.14));
|
||||
|
||||
vm->bind(mod, "add(a: int, b: int)",
|
||||
|
||||
@ -3,7 +3,7 @@ output: .retype
|
||||
url: https://pocketpy.dev
|
||||
branding:
|
||||
title: pocketpy
|
||||
label: v1.5.0
|
||||
label: v2.0.0
|
||||
logo: "./static/logo.png"
|
||||
favicon: "./static/logo.png"
|
||||
meta:
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
3
include/pocketpy.hpp
Normal file
3
include/pocketpy.hpp
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy.h"
|
||||
@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
// generated by prebuild.py
|
||||
|
||||
namespace pkpy{
|
||||
extern const char kPythonLibs__enum[];
|
||||
extern const char kPythonLibs__long[];
|
||||
extern const char kPythonLibs__set[];
|
||||
extern const char kPythonLibs_bisect[];
|
||||
extern const char kPythonLibs_builtins[];
|
||||
extern const char kPythonLibs_cmath[];
|
||||
extern const char kPythonLibs_collections[];
|
||||
extern const char kPythonLibs_colorsys[];
|
||||
extern const char kPythonLibs_datetime[];
|
||||
extern const char kPythonLibs_functools[];
|
||||
extern const char kPythonLibs_heapq[];
|
||||
extern const char kPythonLibs_itertools[];
|
||||
extern const char kPythonLibs_operator[];
|
||||
extern const char kPythonLibs_pickle[];
|
||||
extern const char kPythonLibs_this[];
|
||||
extern const char kPythonLibs_typing[];
|
||||
} // namespace pkpy
|
||||
@ -1,130 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "str.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct any{
|
||||
struct vtable{
|
||||
const std::type_index type;
|
||||
void (*deleter)(void*);
|
||||
|
||||
template<typename T>
|
||||
inline static vtable* get(){
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if constexpr (is_sso_v<T>){
|
||||
static vtable vt{ typeid(T), nullptr };
|
||||
return &vt;
|
||||
}else{
|
||||
static vtable vt{ typeid(T), [](void* ptr){ delete static_cast<T*>(ptr); } };
|
||||
return &vt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void* data;
|
||||
vtable* _vt;
|
||||
|
||||
any() : data(nullptr), _vt(nullptr) {}
|
||||
|
||||
operator bool() const { return _vt != nullptr; }
|
||||
|
||||
template<typename T>
|
||||
any(T&& value){
|
||||
using U = std::decay_t<T>;
|
||||
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
|
||||
static_assert(sizeof(U) == sizeof(T));
|
||||
if constexpr (is_sso_v<U>){
|
||||
memcpy(&data, &value, sizeof(U));
|
||||
}else{
|
||||
data = new U(std::forward<T>(value));
|
||||
}
|
||||
_vt = vtable::get<U>();
|
||||
}
|
||||
|
||||
any(any&& other) noexcept;
|
||||
any& operator=(any&& other) noexcept;
|
||||
|
||||
const std::type_index type_id() const{
|
||||
return _vt ? _vt->type : typeid(void);
|
||||
}
|
||||
|
||||
any(const any& other) = delete;
|
||||
any& operator=(const any& other) = delete;
|
||||
|
||||
~any() { if(_vt && _vt->deleter) _vt->deleter(data); }
|
||||
|
||||
template<typename T>
|
||||
T& _cast() const noexcept{
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if constexpr (is_sso_v<T>){
|
||||
return *((T*)(&data));
|
||||
}else{
|
||||
return *(static_cast<T*>(data));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& cast() const{
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
|
||||
return _cast<T>();
|
||||
}
|
||||
|
||||
static void __bad_any_cast(const std::type_index expected, const std::type_index actual);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct function;
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
struct function<Ret(Params...)>{
|
||||
any _impl;
|
||||
Ret (*_wrapper)(const any&, Params...);
|
||||
|
||||
function(): _impl(), _wrapper(nullptr) {}
|
||||
|
||||
operator bool() const { return _wrapper != nullptr; }
|
||||
|
||||
template<typename F>
|
||||
function(F&& f) : _impl(std::forward<F>(f)){
|
||||
_wrapper = [](const any& impl, Params... params) -> Ret{
|
||||
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
|
||||
};
|
||||
}
|
||||
|
||||
Ret operator()(Params... params) const{
|
||||
if(!_wrapper) throw std::runtime_error("empty function");
|
||||
return _wrapper(_impl, std::forward<Params>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct lightfunction;
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
struct lightfunction<Ret(Params...)>{
|
||||
void* _impl;
|
||||
Ret (*_wrapper)(void*, Params...);
|
||||
|
||||
lightfunction() : _impl(nullptr), _wrapper(nullptr) {}
|
||||
|
||||
operator bool() const { return _wrapper != nullptr; }
|
||||
|
||||
template<typename F>
|
||||
lightfunction(const F& f){
|
||||
_impl = (F*)(&f);
|
||||
_wrapper = [](void* impl, Params... params) -> Ret{
|
||||
F* f = (F*)(impl);
|
||||
return (*f)(std::forward<Params>(params)...);
|
||||
};
|
||||
}
|
||||
|
||||
Ret operator()(Params... params) const{
|
||||
if(!_wrapper) throw std::runtime_error("empty function");
|
||||
return _wrapper(_impl, std::forward<Params>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_array2d(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_base64(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,211 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "cffi.h"
|
||||
#include "vm.h"
|
||||
|
||||
namespace pkpy{
|
||||
struct NativeProxyFuncCBase {
|
||||
virtual PyVar operator()(VM* vm, ArgsView args) = 0;
|
||||
};
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
struct NativeProxyFuncC final: NativeProxyFuncCBase {
|
||||
static constexpr int N = sizeof...(Params);
|
||||
using _Fp = Ret(*)(Params...);
|
||||
_Fp func;
|
||||
NativeProxyFuncC(_Fp func) : func(func) {}
|
||||
|
||||
PyVar operator()(VM* vm, ArgsView args) override {
|
||||
PK_DEBUG_ASSERT(args.size() == N);
|
||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template<typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
|
||||
if constexpr(std::is_void_v<__Ret>){
|
||||
func(py_cast<Params>(vm, args[Is])...);
|
||||
return vm->None;
|
||||
}else{
|
||||
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
struct NativeProxyMethodC final: NativeProxyFuncCBase {
|
||||
static constexpr int N = sizeof...(Params);
|
||||
using _Fp = Ret(T::*)(Params...);
|
||||
_Fp func;
|
||||
NativeProxyMethodC(_Fp func) : func(func) {}
|
||||
|
||||
PyVar operator()(VM* vm, ArgsView args) override {
|
||||
PK_DEBUG_ASSERT(args.size() == N+1);
|
||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template<typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
|
||||
T& self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
|
||||
if constexpr(std::is_void_v<__Ret>){
|
||||
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
||||
return vm->None;
|
||||
}else{
|
||||
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
}
|
||||
};
|
||||
/*****************************************************************/
|
||||
inline PyVar __proxy_wrapper(VM* vm, ArgsView args){
|
||||
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
|
||||
return (*pf)(vm, args);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
PyVar VM::bind(PyVar obj, const char* sig, Ret(*func)(Params...), BindType bt){
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
PyVar VM::bind(PyVar obj, const char* sig, Ret(T::*func)(Params...), BindType bt){
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename T, typename F, bool ReadOnly>
|
||||
PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){
|
||||
static_assert(!std::is_reference_v<F>);
|
||||
PK_ASSERT(is_type(obj, tp_type));
|
||||
std::string_view name_sv(name); int pos = name_sv.find(':');
|
||||
if(pos > 0) name_sv = name_sv.substr(0, pos);
|
||||
auto fget = [](VM* vm, ArgsView args) -> PyVar{
|
||||
T& self = PK_OBJ_GET(T, args[0]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
return VAR(self.*field);
|
||||
};
|
||||
PyVar _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, field);
|
||||
PyVar _1 = vm->None;
|
||||
if constexpr (!ReadOnly){
|
||||
auto fset = [](VM* vm, ArgsView args){
|
||||
T& self = PK_OBJ_GET(T, args[0]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
self.*field = py_cast<F>(vm, args[1]);
|
||||
return vm->None;
|
||||
};
|
||||
_1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, field);
|
||||
}
|
||||
PyVar prop = VAR(Property(_0, _1));
|
||||
obj->attr().set(StrName(name_sv), prop);
|
||||
return prop;
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
[[deprecated]] void _bind(VM* vm, PyVar obj, const char* sig, Ret(*func)(Params...)){
|
||||
return vm->bind(obj, sig, func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
[[deprecated]] void _bind(VM* vm, PyVar obj, const char* sig, Ret(T::*func)(Params...)){
|
||||
return vm->bind(obj, sig, func);
|
||||
}
|
||||
/*****************************************************************/
|
||||
#define PY_FIELD(T, NAME, EXPR) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.EXPR); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = PK_OBJ_GET(T, args[0]); \
|
||||
self.EXPR = CAST(decltype(self.EXPR), args[1]); \
|
||||
return vm->None; \
|
||||
});
|
||||
|
||||
#define PY_READONLY_FIELD(T, NAME, EXPR) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.EXPR); \
|
||||
});
|
||||
|
||||
#define PY_PROPERTY(T, NAME, FGET, FSET) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.FGET()); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = _CAST(T&, args[0]); \
|
||||
using __NT = decltype(self.FGET()); \
|
||||
self.FSET(CAST(__NT, args[1])); \
|
||||
return vm->None; \
|
||||
});
|
||||
|
||||
#define PY_READONLY_PROPERTY(T, NAME, FGET) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.FGET()); \
|
||||
});
|
||||
/*****************************************************************/
|
||||
#define PY_STRUCT_LIKE(wT) \
|
||||
static_assert(std::is_trivially_copyable<wT>::value); \
|
||||
type->attr().set("__struct__", vm->True); \
|
||||
vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
|
||||
Struct& s = CAST(Struct&, args[0]); \
|
||||
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
|
||||
PyVar obj = vm->new_user_object<wT>(); \
|
||||
memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
|
||||
return obj; \
|
||||
}, {}, BindType::STATICMETHOD); \
|
||||
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args){ \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
||||
}); \
|
||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<VoidP>(&self); \
|
||||
}); \
|
||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<wT>(self); \
|
||||
}); \
|
||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \
|
||||
return VAR(sizeof(wT)); \
|
||||
}); \
|
||||
vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
wT& self = _CAST(wT&, _0); \
|
||||
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
||||
wT& other = _CAST(wT&, _1); \
|
||||
return VAR(self == other); \
|
||||
}); \
|
||||
|
||||
#define PY_POINTER_SETGETITEM(T) \
|
||||
vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
VoidP& self = PK_OBJ_GET(VoidP, _0); \
|
||||
i64 i = CAST(i64, _1); \
|
||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||
return VAR(tgt[i]); \
|
||||
}); \
|
||||
vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \
|
||||
VoidP& self = PK_OBJ_GET(VoidP, _0); \
|
||||
i64 i = CAST(i64, _1); \
|
||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||
tgt[i] = CAST(T, _2); \
|
||||
}); \
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "vm.h"
|
||||
// dummy header for ceval.cpp
|
||||
@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "vm.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
#define PY_CLASS(T, mod, name) \
|
||||
[[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \
|
||||
[[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base=Type(0)) { \
|
||||
return vm->register_user_class<T>(mod, #name, base); \
|
||||
}
|
||||
|
||||
struct VoidP{
|
||||
void* ptr;
|
||||
VoidP(const void* ptr): ptr(const_cast<void*>(ptr)){}
|
||||
|
||||
bool operator==(const VoidP& other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
bool operator!=(const VoidP& other) const {
|
||||
return ptr != other.ptr;
|
||||
}
|
||||
bool operator<(const VoidP& other) const { return ptr < other.ptr; }
|
||||
bool operator<=(const VoidP& other) const { return ptr <= other.ptr; }
|
||||
bool operator>(const VoidP& other) const { return ptr > other.ptr; }
|
||||
bool operator>=(const VoidP& other) const { return ptr >= other.ptr; }
|
||||
|
||||
Str hex() const{
|
||||
SStream ss;
|
||||
ss.write_hex(ptr);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
#define POINTER_VAR(Tp, NAME) \
|
||||
inline PyVar py_var(VM* vm, Tp val){ \
|
||||
const static std::pair<StrName, StrName> P("c", NAME); \
|
||||
PyVar type = vm->_modules[P.first]->attr(P.second); \
|
||||
return vm->heap.gcnew<VoidP>(PK_OBJ_GET(Type, type), val); \
|
||||
}
|
||||
|
||||
POINTER_VAR(char*, "char_p")
|
||||
// const char* is special, need to rethink about it
|
||||
POINTER_VAR(const unsigned char*, "uchar_p")
|
||||
POINTER_VAR(const short*, "short_p")
|
||||
POINTER_VAR(const unsigned short*, "ushort_p")
|
||||
POINTER_VAR(const int*, "int_p")
|
||||
POINTER_VAR(const unsigned int*, "uint_p")
|
||||
POINTER_VAR(const long*, "long_p")
|
||||
POINTER_VAR(const unsigned long*, "ulong_p")
|
||||
POINTER_VAR(const long long*, "longlong_p")
|
||||
POINTER_VAR(const unsigned long long*, "ulonglong_p")
|
||||
POINTER_VAR(const float*, "float_p")
|
||||
POINTER_VAR(const double*, "double_p")
|
||||
POINTER_VAR(const bool*, "bool_p")
|
||||
|
||||
#undef POINTER_VAR
|
||||
|
||||
|
||||
struct Struct{
|
||||
static constexpr int INLINE_SIZE = 24;
|
||||
|
||||
char _inlined[INLINE_SIZE];
|
||||
char* p;
|
||||
int size;
|
||||
|
||||
Struct(int new_size, bool zero_init=true){
|
||||
this->size = new_size;
|
||||
if(size <= INLINE_SIZE){
|
||||
p = _inlined;
|
||||
}else{
|
||||
p = (char*)malloc(size);
|
||||
}
|
||||
if(zero_init) memset(p, 0, size);
|
||||
}
|
||||
|
||||
Struct(void* p, int size): Struct(size, false){
|
||||
if(p != nullptr) memcpy(this->p, p, size);
|
||||
}
|
||||
|
||||
Struct(const Struct& other): Struct(other.p, other.size){}
|
||||
~Struct(){ if(p!=_inlined) free(p); }
|
||||
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
static_assert(sizeof(Py_<Struct>) <= 64);
|
||||
static_assert(sizeof(Py_<Tuple>) <= 64);
|
||||
|
||||
/***********************************************/
|
||||
template<typename Tp>
|
||||
Tp to_void_p(VM* vm, PyVar var){
|
||||
static_assert(std::is_pointer_v<Tp>);
|
||||
if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
|
||||
VoidP& p = CAST(VoidP&, var);
|
||||
return reinterpret_cast<Tp>(p.ptr);
|
||||
}
|
||||
/*****************************************************************/
|
||||
void add_module_c(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,181 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "obj.h"
|
||||
#include "error.h"
|
||||
#include "any.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
|
||||
|
||||
enum Opcode: uint8_t {
|
||||
#define OPCODE(name) OP_##name,
|
||||
#include "opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
struct Bytecode{
|
||||
uint8_t op;
|
||||
uint16_t arg;
|
||||
};
|
||||
|
||||
enum class CodeBlockType {
|
||||
NO_BLOCK,
|
||||
FOR_LOOP,
|
||||
WHILE_LOOP,
|
||||
CONTEXT_MANAGER,
|
||||
TRY_EXCEPT,
|
||||
};
|
||||
|
||||
inline const uint8_t BC_NOARG = 0;
|
||||
inline const int BC_KEEPLINE = -1;
|
||||
|
||||
struct CodeBlock {
|
||||
CodeBlockType type;
|
||||
int parent; // parent index in blocks
|
||||
int base_stack_size; // this is used for exception handling
|
||||
int start; // start index of this block in codes, inclusive
|
||||
int end; // end index of this block in codes, exclusive
|
||||
int end2; // ...
|
||||
|
||||
CodeBlock(CodeBlockType type, int parent, int base_stack_size, int start):
|
||||
type(type), parent(parent), base_stack_size(base_stack_size), start(start), end(-1), end2(-1) {}
|
||||
|
||||
int get_break_end() const{
|
||||
if(end2 != -1) return end2;
|
||||
return end;
|
||||
}
|
||||
};
|
||||
|
||||
struct CodeObject;
|
||||
struct FuncDecl;
|
||||
using CodeObject_ = std::shared_ptr<CodeObject>;
|
||||
using FuncDecl_ = std::shared_ptr<FuncDecl>;
|
||||
|
||||
struct CodeObject {
|
||||
struct LineInfo{
|
||||
int lineno; // line number for each bytecode
|
||||
bool is_virtual; // whether this bytecode is virtual (not in source code)
|
||||
};
|
||||
|
||||
std::shared_ptr<SourceData> src;
|
||||
Str name;
|
||||
|
||||
std::vector<Bytecode> codes;
|
||||
std::vector<int> iblocks; // block index for each bytecode
|
||||
std::vector<LineInfo> lines;
|
||||
|
||||
small_vector_2<PyVar, 8> consts; // constants
|
||||
small_vector_2<StrName, 8> varnames; // local variables
|
||||
|
||||
NameDictInt varnames_inv;
|
||||
std::vector<CodeBlock> blocks;
|
||||
NameDictInt labels;
|
||||
std::vector<FuncDecl_> func_decls;
|
||||
|
||||
int start_line;
|
||||
int end_line;
|
||||
|
||||
const CodeBlock& _get_block_codei(int codei) const{
|
||||
return blocks[iblocks[codei]];
|
||||
}
|
||||
|
||||
CodeObject(std::shared_ptr<SourceData> src, const Str& name);
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
enum class FuncType{
|
||||
UNSET,
|
||||
NORMAL,
|
||||
SIMPLE,
|
||||
EMPTY,
|
||||
GENERATOR,
|
||||
};
|
||||
|
||||
struct FuncDecl {
|
||||
struct KwArg {
|
||||
int index; // index in co->varnames
|
||||
StrName key; // name of this argument
|
||||
PyVar value; // default value
|
||||
};
|
||||
CodeObject_ code; // code object of this function
|
||||
|
||||
small_vector_2<int, 6> args; // indices in co->varnames
|
||||
small_vector_2<KwArg, 6> kwargs; // indices in co->varnames
|
||||
|
||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||
bool nested = false; // whether this function is nested
|
||||
|
||||
const char* docstring; // docstring of this function (weak ref)
|
||||
|
||||
FuncType type = FuncType::UNSET;
|
||||
|
||||
NameDictInt kw_to_index;
|
||||
|
||||
void add_kwarg(int index, StrName key, PyVar value){
|
||||
kw_to_index.set(key, index);
|
||||
kwargs.push_back(KwArg{index, key, value});
|
||||
}
|
||||
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
struct NativeFunc {
|
||||
NativeFuncC f;
|
||||
int argc; // old style argc-based call
|
||||
FuncDecl_ decl; // new style decl-based call
|
||||
any _userdata;
|
||||
|
||||
NativeFunc(NativeFuncC f, int argc, any userdata={}): f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
|
||||
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata={}): f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
|
||||
|
||||
void check_size(VM* vm, ArgsView args) const;
|
||||
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
|
||||
};
|
||||
|
||||
struct Function{
|
||||
FuncDecl_ decl;
|
||||
PyVar _module; // weak ref
|
||||
PyVar _class; // weak ref
|
||||
NameDict_ _closure;
|
||||
|
||||
explicit Function(FuncDecl_ decl, PyVar _module, PyVar _class, NameDict_ _closure):
|
||||
decl(decl), _module(_module), _class(_class), _closure(_closure) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Function> final: PyObject {
|
||||
Function _value;
|
||||
template<typename... Args>
|
||||
Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {
|
||||
// _enable_instance_dict();
|
||||
}
|
||||
void _obj_gc_mark() override {
|
||||
_value.decl->_gc_mark();
|
||||
if(_value._closure != nullptr) _gc_mark_namedict(_value._closure.get());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<NativeFunc> final: PyObject {
|
||||
NativeFunc _value;
|
||||
template<typename... Args>
|
||||
Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {
|
||||
// _enable_instance_dict();
|
||||
}
|
||||
void _obj_gc_mark() override {
|
||||
if(_value.decl != nullptr){
|
||||
_value.decl->_gc_mark();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T& lambda_get_userdata(PyVar* p){
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
int offset = p[-1] != PY_NULL ? -1 : -2;
|
||||
return PK_OBJ_GET(NativeFunc, p[offset])._userdata.cast<T>();
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy
|
||||
{
|
||||
void add_module_collections(VM *vm);
|
||||
} // namespace pkpy
|
||||
@ -1,175 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <variant>
|
||||
#include <type_traits>
|
||||
#include <deque>
|
||||
#include <typeindex>
|
||||
#include <initializer_list>
|
||||
|
||||
#define PK_VERSION "1.5.0"
|
||||
|
||||
#include "config.h"
|
||||
#include "export.h"
|
||||
|
||||
#include "_generated.h"
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
/*******************************************************************************/
|
||||
#if PK_ENABLE_STD_FUNCTION
|
||||
#include <functional>
|
||||
#endif
|
||||
/*******************************************************************************/
|
||||
|
||||
#if PK_ENABLE_THREAD
|
||||
#define PK_THREAD_LOCAL thread_local
|
||||
#include <mutex>
|
||||
|
||||
struct GIL {
|
||||
inline static std::mutex _mutex;
|
||||
explicit GIL() { _mutex.lock(); }
|
||||
~GIL() { _mutex.unlock(); }
|
||||
};
|
||||
#define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
|
||||
|
||||
#else
|
||||
#define PK_THREAD_LOCAL
|
||||
#define PK_GLOBAL_SCOPE_LOCK()
|
||||
#endif
|
||||
|
||||
/*******************************************************************************/
|
||||
|
||||
#define PK_UNUSED(x) (void)(x)
|
||||
|
||||
#define PK_LOCAL_STATIC static
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
namespace std = ::std;
|
||||
|
||||
template <size_t T>
|
||||
struct NumberTraits;
|
||||
|
||||
template <>
|
||||
struct NumberTraits<4> {
|
||||
using int_t = int32_t;
|
||||
static constexpr int_t kMaxSmallInt = (1 << 28) - 1;
|
||||
static constexpr int_t kMinSmallInt = 0;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct NumberTraits<8> {
|
||||
using int_t = int64_t;
|
||||
static constexpr int_t kMaxSmallInt = (1ll << 60) - 1;
|
||||
static constexpr int_t kMinSmallInt = 0;
|
||||
};
|
||||
|
||||
using Number = NumberTraits<sizeof(void*)>;
|
||||
using i64 = int64_t; // always 64-bit
|
||||
using f64 = double; // always 64-bit
|
||||
|
||||
static_assert(sizeof(i64) == 8);
|
||||
|
||||
struct Dummy { }; // for special objects: True, False, None, Ellipsis, etc.
|
||||
struct DummyInstance { };
|
||||
struct DummyModule { };
|
||||
struct NoReturn { };
|
||||
struct Discarded { };
|
||||
|
||||
struct Type {
|
||||
int16_t index;
|
||||
constexpr Type(): index(-1) {}
|
||||
explicit constexpr Type(int index): index(index) {}
|
||||
bool operator==(Type other) const { return this->index == other.index; }
|
||||
bool operator!=(Type other) const { return this->index != other.index; }
|
||||
operator int() const { return this->index; }
|
||||
};
|
||||
|
||||
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) { return x; })
|
||||
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) { return VAR(x); })
|
||||
#define PK_ACTION(x) ([](VM* vm, ArgsView args) { x; return vm->None; })
|
||||
|
||||
#define PK_REGION(name) 1
|
||||
|
||||
#ifdef POCKETPY_H
|
||||
#define PK_FATAL_ERROR() throw std::runtime_error( "L" + std::to_string(__LINE__) + " FATAL_ERROR()!");
|
||||
#else
|
||||
#define PK_FATAL_ERROR() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " FATAL_ERROR()!");
|
||||
#endif
|
||||
|
||||
#define PK_ASSERT(x) if(!(x)) PK_FATAL_ERROR();
|
||||
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
#define PK_DEBUG_ASSERT(x) if(!(x)) PK_FATAL_ERROR();
|
||||
#else
|
||||
#define PK_DEBUG_ASSERT(x)
|
||||
#endif
|
||||
|
||||
struct PyObject;
|
||||
using PyVar = PyObject *;
|
||||
#define PK_BITS(p) (reinterpret_cast<i64>(p))
|
||||
|
||||
// is_pod_v<> for c++17 and c++20
|
||||
template<typename T>
|
||||
inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
||||
|
||||
#define PK_ALWAYS_PASS_BY_POINTER(T) \
|
||||
T(const T&) = delete; \
|
||||
T& operator=(const T&) = delete; \
|
||||
T(T&&) = delete; \
|
||||
T& operator=(T&&) = delete;
|
||||
|
||||
inline const char* kPlatformStrings[] = {
|
||||
"win32", // 0
|
||||
"emscripten", // 1
|
||||
"ios", // 2
|
||||
"darwin", // 3
|
||||
"android", // 4
|
||||
"linux", // 5
|
||||
"unknown" // 6
|
||||
};
|
||||
|
||||
#define PK_SLICE_LOOP(i, start, stop, step) for(int i=start; step>0?i<stop:i>stop; i+=step)
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_integral_v = std::is_same_v<T, char>
|
||||
|| std::is_same_v<T, short>
|
||||
|| std::is_same_v<T, int>
|
||||
|| std::is_same_v<T, long>
|
||||
|| std::is_same_v<T, long long>
|
||||
|| std::is_same_v<T, unsigned char>
|
||||
|| std::is_same_v<T, unsigned short>
|
||||
|| std::is_same_v<T, unsigned int>
|
||||
|| std::is_same_v<T, unsigned long>
|
||||
|| std::is_same_v<T, unsigned long long>
|
||||
|| std::is_same_v<T, signed char>; // for imgui
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
|
||||
|
||||
inline const char* PK_HEX_TABLE = "0123456789abcdef";
|
||||
|
||||
} // namespace pkpy
|
||||
18
include/pocketpy/common/_generated.h
Normal file
18
include/pocketpy/common/_generated.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
// generated by prebuild.py
|
||||
|
||||
const char* load_kPythonLib(const char* name);
|
||||
|
||||
extern const char kPythonLibs__enum[];
|
||||
extern const char kPythonLibs_bisect[];
|
||||
extern const char kPythonLibs_builtins[];
|
||||
extern const char kPythonLibs_cmath[];
|
||||
extern const char kPythonLibs_collections[];
|
||||
extern const char kPythonLibs_datetime[];
|
||||
extern const char kPythonLibs_functools[];
|
||||
extern const char kPythonLibs_heapq[];
|
||||
extern const char kPythonLibs_itertools[];
|
||||
extern const char kPythonLibs_operator[];
|
||||
extern const char kPythonLibs_pickle[];
|
||||
extern const char kPythonLibs_this[];
|
||||
extern const char kPythonLibs_typing[];
|
||||
40
include/pocketpy/common/algorithm.h
Normal file
40
include/pocketpy/common/algorithm.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define c11__less(a, b) ((a) < (b))
|
||||
|
||||
#define c11__lower_bound(T, ptr, count, key, less, out_index) \
|
||||
do { \
|
||||
T* __first = ptr; \
|
||||
int __len = count; \
|
||||
while(__len > 8) { \
|
||||
int __l2 = __len >> 1; \
|
||||
T* __m = __first + __l2; \
|
||||
if(less((*__m), (key))) { \
|
||||
__first = ++__m; \
|
||||
__len -= __l2 + 1; \
|
||||
} else { \
|
||||
__len = __l2; \
|
||||
} \
|
||||
} \
|
||||
while(__len && less(*__first, (key))) { \
|
||||
++__first; \
|
||||
--__len; \
|
||||
} \
|
||||
*(out_index) = __first - (T*)(ptr); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief Sorts an array of elements of the same type, using the given comparison function.
|
||||
* @param ptr Pointer to the first element of the array.
|
||||
* @param count Number of elements in the array.
|
||||
* @param elem_size Size of each element in the array.
|
||||
* @param cmp Comparison function that takes two elements and returns an integer similar to
|
||||
* `strcmp`.
|
||||
*/
|
||||
bool c11__stable_sort(void* ptr,
|
||||
int count,
|
||||
int elem_size,
|
||||
int (*f_lt)(const void* a, const void* b, void* extra),
|
||||
void* extra);
|
||||
58
include/pocketpy/common/config.h
Normal file
58
include/pocketpy/common/config.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
#define PK_VERSION "2.0.0"
|
||||
#define PK_VERSION_MAJOR 2
|
||||
#define PK_VERSION_MINOR 0
|
||||
#define PK_VERSION_PATCH 0
|
||||
|
||||
/*************** feature settings ***************/
|
||||
|
||||
// Whether to compile os-related modules or not
|
||||
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
||||
#define PK_ENABLE_OS 1
|
||||
#endif
|
||||
|
||||
// Enable `line_profiler` module and `breakpoint()` function
|
||||
#ifndef PK_ENABLE_PROFILER // can be overridden by cmake
|
||||
#define PK_ENABLE_PROFILER 0
|
||||
#endif
|
||||
|
||||
// GC min threshold
|
||||
#ifndef PK_GC_MIN_THRESHOLD // can be overridden by cmake
|
||||
#define PK_GC_MIN_THRESHOLD 16384
|
||||
#endif
|
||||
|
||||
/*************** debug settings ***************/
|
||||
// Do not edit the following settings unless you know what you are doing
|
||||
#define PK_DEBUG_CEVAL_STEP 0
|
||||
#define PK_DEBUG_MEMORY_POOL 0
|
||||
#define PK_DEBUG_NO_AUTO_GC 0
|
||||
#define PK_DEBUG_GC_STATS 0
|
||||
#define PK_DEBUG_COMPILER 0
|
||||
|
||||
#ifndef PK_DEBUG_PRECOMPILED_EXEC
|
||||
#define PK_DEBUG_PRECOMPILED_EXEC 0
|
||||
#endif
|
||||
|
||||
/*************** internal settings ***************/
|
||||
|
||||
// This is the maximum size of the value stack in py_TValue units
|
||||
// The actual size in bytes equals `sizeof(py_TValue) * PK_VM_STACK_SIZE`
|
||||
#define PK_VM_STACK_SIZE 16384
|
||||
|
||||
// This is the maximum number of local variables in a function
|
||||
// (not recommended to change this)
|
||||
#define PK_MAX_CO_VARNAMES 64
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PK_PLATFORM_SEP '\\'
|
||||
#else
|
||||
#define PK_PLATFORM_SEP '/'
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define PK_DEBUG 0
|
||||
#else
|
||||
#define PK_DEBUG 1
|
||||
#endif
|
||||
@ -1,38 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
// clang-format off
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
//define something for Windows (32-bit and 64-bit, this part is common)
|
||||
#define PK_EXPORT __declspec(dllexport)
|
||||
#define PK_SYS_PLATFORM 0
|
||||
#define PY_SYS_PLATFORM 0
|
||||
#define PY_SYS_PLATFORM_STRING "win32"
|
||||
#elif __EMSCRIPTEN__
|
||||
#define PK_EXPORT
|
||||
#define PK_SYS_PLATFORM 1
|
||||
#define PY_SYS_PLATFORM 1
|
||||
#define PY_SYS_PLATFORM_STRING "emscripten"
|
||||
#elif __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
// iOS, tvOS, or watchOS Simulator
|
||||
#define PK_SYS_PLATFORM 2
|
||||
#define PY_SYS_PLATFORM 2
|
||||
#define PY_SYS_PLATFORM_STRING "ios"
|
||||
#elif TARGET_OS_IPHONE
|
||||
// iOS, tvOS, or watchOS device
|
||||
#define PK_SYS_PLATFORM 2
|
||||
#define PY_SYS_PLATFORM 2
|
||||
#define PY_SYS_PLATFORM_STRING "ios"
|
||||
#elif TARGET_OS_MAC
|
||||
#define PK_SYS_PLATFORM 3
|
||||
#define PY_SYS_PLATFORM 3
|
||||
#define PY_SYS_PLATFORM_STRING "darwin"
|
||||
#else
|
||||
# error "Unknown Apple platform"
|
||||
#endif
|
||||
#define PK_EXPORT __attribute__((visibility("default")))
|
||||
#elif __ANDROID__
|
||||
#define PK_EXPORT __attribute__((visibility("default")))
|
||||
#define PK_SYS_PLATFORM 4
|
||||
#define PY_SYS_PLATFORM 4
|
||||
#define PY_SYS_PLATFORM_STRING "android"
|
||||
#elif __linux__
|
||||
#define PK_EXPORT __attribute__((visibility("default")))
|
||||
#define PK_SYS_PLATFORM 5
|
||||
#define PY_SYS_PLATFORM 5
|
||||
#define PY_SYS_PLATFORM_STRING "linux"
|
||||
#else
|
||||
#define PK_EXPORT
|
||||
#define PK_SYS_PLATFORM 6
|
||||
#define PY_SYS_PLATFORM 6
|
||||
#define PY_SYS_PLATFORM_STRING "unknown"
|
||||
#endif
|
||||
|
||||
#if PK_SYS_PLATFORM == 0 || PK_SYS_PLATFORM == 3 || PK_SYS_PLATFORM == 5
|
||||
#if PY_SYS_PLATFORM == 0 || PY_SYS_PLATFORM == 3 || PY_SYS_PLATFORM == 5
|
||||
#define PK_IS_DESKTOP_PLATFORM 1
|
||||
#else
|
||||
#define PK_IS_DESKTOP_PLATFORM 0
|
||||
22
include/pocketpy/common/memorypool.h
Normal file
22
include/pocketpy/common/memorypool.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#define kPoolExprBlockSize 128
|
||||
#define kPoolFrameBlockSize 80
|
||||
#define kPoolObjectBlockSize 80
|
||||
|
||||
#define kPoolObjectArenaSize (256*1024)
|
||||
#define kPoolObjectMaxBlocks (kPoolObjectArenaSize / kPoolObjectBlockSize)
|
||||
|
||||
void MemoryPools__initialize();
|
||||
void MemoryPools__finalize();
|
||||
|
||||
void* PoolExpr_alloc();
|
||||
void PoolExpr_dealloc(void*);
|
||||
void* PoolFrame_alloc();
|
||||
void PoolFrame_dealloc(void*);
|
||||
|
||||
void* PoolObject_alloc();
|
||||
void PoolObject_dealloc(void* p);
|
||||
void PoolObject_shrink_to_fit();
|
||||
|
||||
void Pools_debug_info(char* buffer, int size);
|
||||
22
include/pocketpy/common/smallmap.h
Normal file
22
include/pocketpy/common/smallmap.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K uint16_t
|
||||
#define V int
|
||||
#define NAME c11_smallmap_n2i
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K c11_sv
|
||||
#define V uint16_t
|
||||
#define NAME c11_smallmap_s2n
|
||||
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
|
||||
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
32
include/pocketpy/common/sstream.h
Normal file
32
include/pocketpy/common/sstream.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct c11_sbuf {
|
||||
c11_vector data;
|
||||
} c11_sbuf;
|
||||
|
||||
void c11_sbuf__ctor(c11_sbuf* self);
|
||||
void c11_sbuf__dtor(c11_sbuf* self);
|
||||
|
||||
void c11_sbuf__write_int(c11_sbuf* self, int);
|
||||
void c11_sbuf__write_i64(c11_sbuf* self, int64_t);
|
||||
void c11_sbuf__write_f64(c11_sbuf* self, double, int precision);
|
||||
void c11_sbuf__write_char(c11_sbuf* self, char);
|
||||
void c11_sbuf__write_pad(c11_sbuf* self, int count, char pad);
|
||||
void c11_sbuf__write_sv(c11_sbuf* self, c11_sv);
|
||||
void c11_sbuf__write_cstr(c11_sbuf* self, const char*);
|
||||
void c11_sbuf__write_cstrn(c11_sbuf* self, const char*, int);
|
||||
void c11_sbuf__write_quoted(c11_sbuf* self, c11_sv, char quote);
|
||||
void c11_sbuf__write_hex(c11_sbuf* self, unsigned char, bool non_zero);
|
||||
void c11_sbuf__write_ptr(c11_sbuf* self, void*);
|
||||
// Submit the stream and return the final string. The stream becomes invalid after this call
|
||||
c11_string* c11_sbuf__submit(c11_sbuf* self);
|
||||
void c11_sbuf__py_submit(c11_sbuf* self, py_Ref out);
|
||||
|
||||
void pk_vsprintf(c11_sbuf* ss, const char* fmt, va_list args);
|
||||
void pk_sprintf(c11_sbuf* ss, const char* fmt, ...);
|
||||
72
include/pocketpy/common/str.h
Normal file
72
include/pocketpy/common/str.h
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
/* string */
|
||||
typedef struct c11_string{
|
||||
// int size | char[] | '\0'
|
||||
int size;
|
||||
const char data[]; // flexible array member
|
||||
} c11_string;
|
||||
|
||||
/* bytes */
|
||||
typedef struct c11_bytes{
|
||||
int size;
|
||||
unsigned char data[]; // flexible array member
|
||||
} c11_bytes;
|
||||
|
||||
bool c11_bytes__eq(c11_bytes* self, c11_bytes* other);
|
||||
|
||||
int c11_sv__cmp(c11_sv self, c11_sv other);
|
||||
int c11_sv__cmp2(c11_sv self, const char* other);
|
||||
|
||||
bool c11__streq(const char* a, const char* b);
|
||||
bool c11__sveq(c11_sv a, c11_sv b);
|
||||
bool c11__sveq2(c11_sv a, const char* b);
|
||||
|
||||
c11_string* c11_string__new(const char* data);
|
||||
c11_string* c11_string__new2(const char* data, int size);
|
||||
c11_string* c11_string__new3(const char* fmt, ...);
|
||||
void c11_string__ctor(c11_string* self, const char* data);
|
||||
void c11_string__ctor2(c11_string* self, const char* data, int size);
|
||||
c11_string* c11_string__copy(c11_string* self);
|
||||
void c11_string__delete(c11_string* self);
|
||||
c11_sv c11_string__sv(c11_string* self);
|
||||
|
||||
int c11_sv__u8_length(c11_sv self);
|
||||
c11_sv c11_sv__u8_getitem(c11_sv self, int i);
|
||||
c11_string* c11_sv__u8_slice(c11_sv self, int start, int stop, int step);
|
||||
|
||||
// general string operations
|
||||
c11_sv c11_sv__slice(c11_sv sv, int start);
|
||||
c11_sv c11_sv__slice2(c11_sv sv, int start, int stop);
|
||||
c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right);
|
||||
int c11_sv__index(c11_sv self, char c);
|
||||
int c11_sv__rindex(c11_sv self, char c);
|
||||
int c11_sv__index2(c11_sv self, c11_sv sub, int start);
|
||||
int c11_sv__count(c11_sv self, c11_sv sub);
|
||||
bool c11_sv__startswith(c11_sv self, c11_sv prefix);
|
||||
bool c11_sv__endswith(c11_sv self, c11_sv suffix);
|
||||
|
||||
c11_string* c11_sv__replace(c11_sv self, char old, char new_);
|
||||
c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_);
|
||||
|
||||
c11_vector/* T=c11_sv */ c11_sv__split(c11_sv self, char sep);
|
||||
c11_vector/* T=c11_sv */ c11_sv__split2(c11_sv self, c11_sv sep);
|
||||
|
||||
// misc
|
||||
int c11__unicode_index_to_byte(const char* data, int i);
|
||||
int c11__byte_index_to_unicode(const char* data, int n);
|
||||
|
||||
bool c11__is_unicode_Lo_char(int c);
|
||||
int c11__u8_header(unsigned char c, bool suppress);
|
||||
|
||||
typedef enum IntParsingResult{
|
||||
IntParsing_SUCCESS,
|
||||
IntParsing_FAILURE,
|
||||
IntParsing_OVERFLOW,
|
||||
} IntParsingResult;
|
||||
|
||||
IntParsingResult c11__parse_uint(c11_sv text, int64_t* out, int base);
|
||||
7
include/pocketpy/common/strname.h
Normal file
7
include/pocketpy/common/strname.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "pocketpy/common/str.h"
|
||||
|
||||
void py_Name__initialize();
|
||||
void py_Name__finalize();
|
||||
50
include/pocketpy/common/utils.h
Normal file
50
include/pocketpy/common/utils.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#define PK_REGION(name) 1
|
||||
|
||||
#define PK_SLICE_LOOP(i, start, stop, step) \
|
||||
for(int i = start; step > 0 ? i < stop : i > stop; i += step)
|
||||
|
||||
// global constants
|
||||
#define PK_HEX_TABLE "0123456789abcdef"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define c11__unreachedable() __assume(0)
|
||||
#else
|
||||
#define c11__unreachedable() __builtin_unreachable()
|
||||
#endif
|
||||
|
||||
#define c11__abort(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
putchar('\n'); \
|
||||
abort(); \
|
||||
} while(0)
|
||||
|
||||
#define c11__min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define c11__max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define c11__count_array(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
// NARGS
|
||||
#define PK_NARGS_SEQ(_1, _2, _3, _4, N, ...) N
|
||||
#define PK_NARGS(...) PK_NARGS_SEQ(__VA_ARGS__, 4, 3, 2, 1, 0)
|
||||
#define PK_NPTRS(...) PK_NARGS_SEQ(__VA_ARGS__, int****, int***, int**, int*, int)
|
||||
|
||||
// ref counting
|
||||
typedef struct RefCounted {
|
||||
int count;
|
||||
void (*dtor)(void*);
|
||||
} RefCounted;
|
||||
|
||||
#define PK_INCREF(obj) (obj)->rc.count++
|
||||
#define PK_DECREF(obj) \
|
||||
do { \
|
||||
if(--(obj)->rc.count == 0) { \
|
||||
(obj)->rc.dtor(obj); \
|
||||
free(obj); \
|
||||
} \
|
||||
} while(0)
|
||||
90
include/pocketpy/common/vector.h
Normal file
90
include/pocketpy/common/vector.h
Normal file
@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/algorithm.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct c11_array {
|
||||
void* data;
|
||||
int count;
|
||||
int elem_size;
|
||||
} c11_array;
|
||||
|
||||
void c11_array__ctor(c11_array* self, int elem_size, int count);
|
||||
void c11_array__dtor(c11_array* self);
|
||||
c11_array c11_array__copy(const c11_array* self);
|
||||
|
||||
typedef struct c11_vector {
|
||||
void* data;
|
||||
int count;
|
||||
int capacity;
|
||||
int elem_size;
|
||||
} c11_vector;
|
||||
|
||||
void c11_vector__ctor(c11_vector* self, int elem_size);
|
||||
void c11_vector__dtor(c11_vector* self);
|
||||
c11_vector c11_vector__copy(const c11_vector* self);
|
||||
void c11_vector__reserve(c11_vector* self, int capacity);
|
||||
void c11_vector__clear(c11_vector* self);
|
||||
void* c11_vector__emplace(c11_vector* self);
|
||||
bool c11_vector__contains(const c11_vector* self, void* elem);
|
||||
c11_array c11_vector__submit(c11_vector* self);
|
||||
|
||||
#define c11__getitem(T, self, index) (((T*)(self)->data)[index])
|
||||
#define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;
|
||||
#define c11__at(T, self, index) ((T*)(self)->data + index)
|
||||
|
||||
#define c11_vector__push(T, self, elem) \
|
||||
do { \
|
||||
if((self)->count == (self)->capacity) c11_vector__reserve((self), (self)->capacity * 2); \
|
||||
((T*)(self)->data)[(self)->count] = (elem); \
|
||||
(self)->count++; \
|
||||
} while(0)
|
||||
|
||||
#define c11_vector__pop(self) (--(self)->count)
|
||||
|
||||
#define c11_vector__back(T, self) (((T*)(self)->data)[(self)->count - 1])
|
||||
|
||||
#define c11_vector__extend(T, self, p, size) \
|
||||
do { \
|
||||
c11_vector__reserve((self), (self)->count + (size)); \
|
||||
memcpy((T*)(self)->data + (self)->count, (p), (size) * sizeof(T)); \
|
||||
(self)->count += (size); \
|
||||
} while(0)
|
||||
|
||||
#define c11_vector__insert(T, self, index, elem) \
|
||||
do { \
|
||||
if((self)->count == (self)->capacity) c11_vector__reserve((self), (self)->capacity * 2); \
|
||||
T* p = (T*)(self)->data + (index); \
|
||||
memmove(p + 1, p, ((self)->count - (index)) * sizeof(T)); \
|
||||
*p = (elem); \
|
||||
(self)->count++; \
|
||||
} while(0)
|
||||
|
||||
#define c11_vector__erase(T, self, index) \
|
||||
do { \
|
||||
T* p = (T*)(self)->data + (index); \
|
||||
memmove(p, p + 1, ((self)->count - (index)-1) * sizeof(T)); \
|
||||
(self)->count--; \
|
||||
} while(0)
|
||||
|
||||
#define c11__reverse(T, self) \
|
||||
do { \
|
||||
if(!self->data) break; \
|
||||
T* p = (T*)(self)->data; \
|
||||
T* q = (T*)(self)->data + (self)->count - 1; \
|
||||
while(p < q) { \
|
||||
T tmp = *p; \
|
||||
*p = *q; \
|
||||
*q = tmp; \
|
||||
p++; \
|
||||
q--; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
// NOTE: here we do an extra NULL check for it to avoid UB
|
||||
#define c11__foreach(T, self, it) \
|
||||
for(T* it = (self)->data; it && it != (T*)(self)->data + (self)->count; it++)
|
||||
@ -1,144 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "codeobject.h"
|
||||
#include "common.h"
|
||||
#include "expr.h"
|
||||
#include "obj.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
class Compiler;
|
||||
typedef void (Compiler::*PrattCallback)();
|
||||
|
||||
struct PrattRule{
|
||||
PrattCallback prefix;
|
||||
PrattCallback infix;
|
||||
Precedence precedence;
|
||||
};
|
||||
|
||||
class Compiler {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Compiler)
|
||||
|
||||
static PrattRule rules[kTokenCount];
|
||||
|
||||
Lexer lexer;
|
||||
stack_no_copy<CodeEmitContext> contexts;
|
||||
VM* vm;
|
||||
bool unknown_global_scope; // for eval/exec() call
|
||||
// for parsing token stream
|
||||
int i = 0;
|
||||
std::vector<Token> tokens;
|
||||
|
||||
const Token& prev() const{ return tokens.at(i-1); }
|
||||
const Token& curr() const{ return tokens.at(i); }
|
||||
const Token& next() const{ return tokens.at(i+1); }
|
||||
const Token& err() const{
|
||||
if(i >= tokens.size()) return prev();
|
||||
return curr();
|
||||
}
|
||||
void advance(int delta=1) { i += delta; }
|
||||
|
||||
CodeEmitContext* ctx() { return &contexts.top(); }
|
||||
CompileMode mode() const{ return lexer.src->mode; }
|
||||
NameScope name_scope() const;
|
||||
CodeObject_ push_global_context();
|
||||
FuncDecl_ push_f_context(Str name);
|
||||
void pop_context();
|
||||
|
||||
static void init_pratt_rules();
|
||||
|
||||
bool match(TokenIndex expected);
|
||||
void consume(TokenIndex expected);
|
||||
bool match_newlines_repl();
|
||||
|
||||
bool match_newlines(bool repl_throw=false);
|
||||
bool match_end_stmt();
|
||||
void consume_end_stmt();
|
||||
|
||||
/*************************************************/
|
||||
void EXPR();
|
||||
void EXPR_TUPLE(bool allow_slice=false);
|
||||
Expr_ EXPR_VARS(); // special case for `for loop` and `comp`
|
||||
|
||||
template <typename T, typename... Args>
|
||||
unique_ptr_128<T> make_expr(Args&&... args) {
|
||||
void* p = pool128_alloc(sizeof(T));
|
||||
unique_ptr_128<T> expr(new (p) T(std::forward<Args>(args)...));
|
||||
expr->line = prev().line;
|
||||
return expr;
|
||||
}
|
||||
|
||||
void consume_comp(unique_ptr_128<CompExpr> ce, Expr_ expr);
|
||||
|
||||
void exprLiteral();
|
||||
void exprLong();
|
||||
void exprImag();
|
||||
void exprBytes();
|
||||
void exprFString();
|
||||
void exprLambda();
|
||||
void exprOr();
|
||||
void exprAnd();
|
||||
void exprTernary();
|
||||
void exprBinaryOp();
|
||||
void exprNot();
|
||||
void exprUnaryOp();
|
||||
void exprGroup();
|
||||
void exprList();
|
||||
void exprMap();
|
||||
void exprCall();
|
||||
void exprName();
|
||||
void exprAttrib();
|
||||
void exprSlice0();
|
||||
void exprSlice1();
|
||||
void exprSubscr();
|
||||
void exprLiteral0();
|
||||
|
||||
void compile_block_body(void (Compiler::*callback)()=nullptr);
|
||||
void compile_normal_import();
|
||||
void compile_from_import();
|
||||
bool is_expression(bool allow_slice=false);
|
||||
void parse_expression(int precedence, bool allow_slice=false);
|
||||
void compile_if_stmt();
|
||||
void compile_while_loop();
|
||||
void compile_for_loop();
|
||||
void compile_try_except();
|
||||
void compile_decorated();
|
||||
|
||||
bool try_compile_assignment();
|
||||
void compile_stmt();
|
||||
void consume_type_hints();
|
||||
void _add_decorators(const Expr_vector& decorators);
|
||||
void compile_class(const Expr_vector& decorators={});
|
||||
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
|
||||
void compile_function(const Expr_vector& decorators={});
|
||||
|
||||
PyVar to_object(const TokenValue& value);
|
||||
PyVar read_literal();
|
||||
|
||||
void SyntaxError(Str msg){ lexer.throw_err("SyntaxError", msg, err().line, err().start); }
|
||||
void SyntaxError(){ lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
|
||||
void IndentationError(Str msg){ lexer.throw_err("IndentationError", msg, err().line, err().start); }
|
||||
|
||||
public:
|
||||
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false);
|
||||
Str precompile();
|
||||
void from_precompiled(const char* source);
|
||||
CodeObject_ compile();
|
||||
};
|
||||
|
||||
struct TokenDeserializer{
|
||||
const char* curr;
|
||||
const char* source;
|
||||
|
||||
TokenDeserializer(const char* source): curr(source), source(source) {}
|
||||
char read_char(){ return *curr++; }
|
||||
bool match_char(char c){ if(*curr == c) { curr++; return true; } return false; }
|
||||
|
||||
std::string_view read_string(char c);
|
||||
Str read_string_from_hex(char c);
|
||||
int read_count();
|
||||
i64 read_uint(char c);
|
||||
f64 read_float(char c);
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
8
include/pocketpy/compiler/compiler.h
Normal file
8
include/pocketpy/compiler/compiler.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/compiler/lexer.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
|
||||
Error* pk_compile(SourceData_ src, CodeObject* out);
|
||||
93
include/pocketpy/compiler/lexer.h
Normal file
93
include/pocketpy/compiler/lexer.h
Normal file
@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/error.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern const char* TokenSymbols[];
|
||||
|
||||
typedef enum TokenIndex{
|
||||
TK_EOF, TK_EOL, TK_SOF,
|
||||
TK_ID, TK_NUM, TK_STR, TK_FSTR, TK_BYTES, TK_IMAG,
|
||||
TK_INDENT, TK_DEDENT,
|
||||
/***************/
|
||||
TK_IS_NOT, TK_NOT_IN, TK_YIELD_FROM,
|
||||
/***************/
|
||||
TK_ADD, TK_IADD, TK_SUB, TK_ISUB,
|
||||
TK_MUL, TK_IMUL, TK_DIV, TK_IDIV, TK_FLOORDIV, TK_IFLOORDIV, TK_MOD, TK_IMOD,
|
||||
TK_AND, TK_IAND, TK_OR, TK_IOR, TK_XOR, TK_IXOR,
|
||||
TK_LSHIFT, TK_ILSHIFT, TK_RSHIFT, TK_IRSHIFT,
|
||||
/***************/
|
||||
TK_LPAREN, TK_RPAREN, TK_LBRACKET, TK_RBRACKET, TK_LBRACE, TK_RBRACE,
|
||||
TK_DOT, TK_DOTDOT, TK_DOTDOTDOT, TK_COMMA, TK_COLON, TK_SEMICOLON,
|
||||
TK_POW, TK_ARROW, TK_HASH, TK_DECORATOR,
|
||||
TK_GT, TK_LT, TK_ASSIGN, TK_EQ, TK_NE, TK_GE, TK_LE, TK_INVERT,
|
||||
/***************/
|
||||
TK_FALSE, TK_NONE, TK_TRUE, TK_AND_KW, TK_AS, TK_ASSERT, TK_BREAK, TK_CLASS, TK_CONTINUE,
|
||||
TK_DEF, TK_DEL, TK_ELIF, TK_ELSE, TK_EXCEPT, TK_FINALLY, TK_FOR, TK_FROM, TK_GLOBAL,
|
||||
TK_IF, TK_IMPORT, TK_IN, TK_IS, TK_LAMBDA, TK_NOT_KW, TK_OR_KW, TK_PASS, TK_RAISE, TK_RETURN,
|
||||
TK_TRY, TK_WHILE, TK_WITH, TK_YIELD,
|
||||
/***************/
|
||||
TK__COUNT__
|
||||
} TokenIndex;
|
||||
|
||||
enum TokenValueIndex{
|
||||
TokenValue_EMPTY = 0,
|
||||
TokenValue_I64 = 1,
|
||||
TokenValue_F64 = 2,
|
||||
TokenValue_STR = 3,
|
||||
};
|
||||
|
||||
typedef struct TokenValue {
|
||||
enum TokenValueIndex index; // 0: empty
|
||||
union {
|
||||
int64_t _i64; // 1
|
||||
double _f64; // 2
|
||||
c11_string* _str; // 3
|
||||
};
|
||||
} TokenValue;
|
||||
|
||||
typedef struct Token {
|
||||
TokenIndex type;
|
||||
const char* start;
|
||||
int length;
|
||||
int line;
|
||||
int brackets_level;
|
||||
TokenValue value;
|
||||
} Token;
|
||||
|
||||
// https://docs.python.org/3/reference/expressions.html#operator-precedence
|
||||
enum Precedence {
|
||||
PREC_LOWEST = 0,
|
||||
PREC_LAMBDA, // lambda
|
||||
PREC_TERNARY, // ?:
|
||||
PREC_LOGICAL_OR, // or
|
||||
PREC_LOGICAL_AND, // and
|
||||
PREC_LOGICAL_NOT, // not
|
||||
/* https://docs.python.org/3/reference/expressions.html#comparisons
|
||||
* Unlike C, all comparison operations in Python have the same priority,
|
||||
* which is lower than that of any arithmetic, shifting or bitwise operation.
|
||||
* Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics.
|
||||
*/
|
||||
PREC_COMPARISION, // < > <= >= != ==, in / is / is not / not in
|
||||
PREC_BITWISE_OR, // |
|
||||
PREC_BITWISE_XOR, // ^
|
||||
PREC_BITWISE_AND, // &
|
||||
PREC_BITWISE_SHIFT, // << >>
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / % // @
|
||||
PREC_UNARY, // - not ~
|
||||
PREC_EXPONENT, // **
|
||||
PREC_PRIMARY, // f() x[] a.b 1:2
|
||||
PREC_HIGHEST,
|
||||
};
|
||||
|
||||
typedef c11_array TokenArray;
|
||||
|
||||
Error* Lexer__process(SourceData_ src, TokenArray* out_tokens);
|
||||
Error* Lexer__process_and_dump(SourceData_ src, c11_string** out_string);
|
||||
void TokenArray__dtor(TokenArray* self);
|
||||
|
||||
#define Token__sv(self) (c11_sv){(self)->start, (self)->length}
|
||||
@ -1,82 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*************** feature settings ***************/
|
||||
|
||||
// Whether to compile os-related modules or not
|
||||
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
||||
#define PK_ENABLE_OS 0
|
||||
#endif
|
||||
|
||||
// Enable this if you are working with multi-threading (experimental)
|
||||
// This triggers necessary locks to make the VM thread-safe
|
||||
#ifndef PK_ENABLE_THREAD // can be overridden by cmake
|
||||
#define PK_ENABLE_THREAD 0
|
||||
#endif
|
||||
|
||||
// Enable `line_profiler` module and `breakpoint()` function
|
||||
#ifndef PK_ENABLE_PROFILER // can be overridden by cmake
|
||||
#define PK_ENABLE_PROFILER 0
|
||||
#endif
|
||||
|
||||
// GC min threshold
|
||||
#ifndef PK_GC_MIN_THRESHOLD // can be overridden by cmake
|
||||
#define PK_GC_MIN_THRESHOLD 32768
|
||||
#endif
|
||||
|
||||
// Whether to use `std::function` to do bindings or not
|
||||
// By default, functions to be binded must be a C function pointer without capture
|
||||
// However, someone thinks it's not convenient.
|
||||
// By setting this to 1, capturing lambdas can be binded,
|
||||
// but it's slower and may cause severe "code bloat", also needs more time to compile.
|
||||
#define PK_ENABLE_STD_FUNCTION 0
|
||||
|
||||
/*************** debug settings ***************/
|
||||
|
||||
// Enable this may help you find bugs
|
||||
#define PK_DEBUG_EXTRA_CHECK 0
|
||||
|
||||
// Do not edit the following settings unless you know what you are doing
|
||||
#define PK_DEBUG_CEVAL_STEP 0
|
||||
#define PK_DEBUG_MEMORY_POOL 0
|
||||
#define PK_DEBUG_NO_MEMORY_POOL 0
|
||||
#define PK_DEBUG_NO_AUTO_GC 0
|
||||
#define PK_DEBUG_GC_STATS 0
|
||||
|
||||
#ifndef PK_DEBUG_PRECOMPILED_EXEC
|
||||
#define PK_DEBUG_PRECOMPILED_EXEC 0
|
||||
#endif
|
||||
|
||||
/*************** internal settings ***************/
|
||||
|
||||
// This is the maximum size of the value stack in void* units
|
||||
// The actual size in bytes equals `sizeof(void*) * PK_VM_STACK_SIZE`
|
||||
#define PK_VM_STACK_SIZE 32768
|
||||
|
||||
// This is the maximum number of local variables in a function
|
||||
// (not recommended to change this / it should be less than 200)
|
||||
#define PK_MAX_CO_VARNAMES 64
|
||||
|
||||
// Hash table load factor (smaller ones mean less collision but more memory)
|
||||
// For class instance
|
||||
#define PK_INST_ATTR_LOAD_FACTOR 0.67
|
||||
// For class itself
|
||||
#define PK_TYPE_ATTR_LOAD_FACTOR 0.5
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PK_PLATFORM_SEP '\\'
|
||||
#else
|
||||
#define PK_PLATFORM_SEP '/'
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable:4267)
|
||||
#pragma warning (disable:4100)
|
||||
#pragma warning (disable:4244)
|
||||
#pragma warning (disable:4996)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define PK_UNREACHABLE() __assume(0);
|
||||
#else
|
||||
#define PK_UNREACHABLE() __builtin_unreachable();
|
||||
#endif
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_csv(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
void add_module_dataclasses(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "obj.h"
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "str.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
struct Dict{
|
||||
struct Item{
|
||||
PyVar first;
|
||||
PyVar second;
|
||||
};
|
||||
|
||||
struct ItemNode{
|
||||
int prev;
|
||||
int next;
|
||||
};
|
||||
|
||||
static constexpr int __Capacity = 8;
|
||||
static constexpr float __LoadFactor = 0.67f;
|
||||
static_assert(sizeof(Item) * __Capacity <= 128);
|
||||
static_assert(sizeof(ItemNode) * __Capacity <= 64);
|
||||
|
||||
VM* vm;
|
||||
int _capacity;
|
||||
int _mask;
|
||||
int _size;
|
||||
int _critical_size;
|
||||
int _head_idx; // for order preserving
|
||||
int _tail_idx; // for order preserving
|
||||
Item* _items;
|
||||
ItemNode* _nodes; // for order preserving
|
||||
|
||||
Dict(VM* vm);
|
||||
Dict(Dict&& other);
|
||||
Dict(const Dict& other);
|
||||
Dict& operator=(const Dict&) = delete;
|
||||
Dict& operator=(Dict&&) = delete;
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
void _probe_0(PyVar key, bool& ok, int& i) const;
|
||||
void _probe_1(PyVar key, bool& ok, int& i) const;
|
||||
|
||||
void set(PyVar key, PyVar val);
|
||||
void _rehash();
|
||||
|
||||
PyVar try_get(PyVar key) const;
|
||||
|
||||
bool contains(PyVar key) const;
|
||||
bool erase(PyVar key);
|
||||
void update(const Dict& other);
|
||||
|
||||
template<typename __Func>
|
||||
void apply(__Func f) const {
|
||||
int i = _head_idx;
|
||||
while(i != -1){
|
||||
f(_items[i].first, _items[i].second);
|
||||
i = _nodes[i].next;
|
||||
}
|
||||
}
|
||||
|
||||
Tuple keys() const;
|
||||
Tuple values() const;
|
||||
void clear();
|
||||
~Dict();
|
||||
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
void add_module_easing(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,84 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "namedict.h"
|
||||
#include "str.h"
|
||||
#include "tuplelist.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
struct NeedMoreLines {
|
||||
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
|
||||
bool is_compiling_class;
|
||||
};
|
||||
|
||||
struct HandledException {};
|
||||
struct UnhandledException {};
|
||||
struct ToBeRaisedException {};
|
||||
|
||||
enum CompileMode {
|
||||
EXEC_MODE,
|
||||
EVAL_MODE,
|
||||
REPL_MODE,
|
||||
JSON_MODE,
|
||||
CELL_MODE
|
||||
};
|
||||
|
||||
struct SourceData {
|
||||
PK_ALWAYS_PASS_BY_POINTER(SourceData)
|
||||
|
||||
Str filename;
|
||||
CompileMode mode;
|
||||
|
||||
Str source;
|
||||
pod_vector<const char*> line_starts;
|
||||
|
||||
bool is_precompiled;
|
||||
std::vector<Str> _precompiled_tokens;
|
||||
|
||||
SourceData(std::string_view source, const Str& filename, CompileMode mode);
|
||||
SourceData(const Str& filename, CompileMode mode);
|
||||
std::pair<const char*,const char*> _get_line(int lineno) const;
|
||||
std::string_view get_line(int lineno) const;
|
||||
Str snapshot(int lineno, const char* cursor, std::string_view name) const;
|
||||
};
|
||||
|
||||
struct ExceptionLine{
|
||||
std::shared_ptr<SourceData> src;
|
||||
int lineno;
|
||||
const char* cursor;
|
||||
std::string name;
|
||||
|
||||
Str snapshot() const { return src->snapshot(lineno, cursor, name); }
|
||||
|
||||
ExceptionLine(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name):
|
||||
src(src), lineno(lineno), cursor(cursor), name(name) {}
|
||||
};
|
||||
|
||||
struct Exception {
|
||||
StrName type;
|
||||
Str msg;
|
||||
bool is_re;
|
||||
|
||||
int _ip_on_error;
|
||||
void* _code_on_error;
|
||||
|
||||
PyVar _self; // weak reference
|
||||
|
||||
stack<ExceptionLine> stacktrace;
|
||||
Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
|
||||
|
||||
PyVar self() const{
|
||||
PK_ASSERT(_self != nullptr);
|
||||
return _self;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void st_push(Args&&... args){
|
||||
if(stacktrace.size() >= 7) return;
|
||||
stacktrace.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
Str summary() const;
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,379 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "codeobject.h"
|
||||
#include "common.h"
|
||||
#include "lexer.h"
|
||||
#include "error.h"
|
||||
#include "vm.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
struct CodeEmitContext;
|
||||
struct Expr;
|
||||
|
||||
#define PK_POOL128_DELETE(ptr) if(ptr != nullptr) { ptr->~T(); pool128_dealloc(ptr); ptr = nullptr; }
|
||||
|
||||
template<typename T>
|
||||
class unique_ptr_128{
|
||||
T* ptr;
|
||||
public:
|
||||
unique_ptr_128(): ptr(nullptr) {}
|
||||
unique_ptr_128(T* ptr): ptr(ptr) {}
|
||||
T* operator->() const { return ptr; }
|
||||
T* get() const { return ptr; }
|
||||
T* detach() { T* p = ptr; ptr = nullptr; return p; }
|
||||
|
||||
unique_ptr_128(const unique_ptr_128&) = delete;
|
||||
unique_ptr_128& operator=(const unique_ptr_128&) = delete;
|
||||
|
||||
bool operator==(std::nullptr_t) const { return ptr == nullptr; }
|
||||
bool operator!=(std::nullptr_t) const { return ptr != nullptr; }
|
||||
|
||||
~unique_ptr_128(){ PK_POOL128_DELETE(ptr) }
|
||||
|
||||
template<typename U>
|
||||
unique_ptr_128(unique_ptr_128<U>&& other): ptr(other.detach()) {}
|
||||
|
||||
operator bool() const { return ptr != nullptr; }
|
||||
|
||||
template<typename U>
|
||||
unique_ptr_128& operator=(unique_ptr_128<U>&& other) {
|
||||
PK_POOL128_DELETE(ptr)
|
||||
ptr = other.detach();
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr_128& operator=(std::nullptr_t) {
|
||||
PK_POOL128_DELETE(ptr)
|
||||
ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
typedef unique_ptr_128<Expr> Expr_;
|
||||
typedef small_vector<Expr_, 4> Expr_vector;
|
||||
|
||||
template<>
|
||||
struct TriviallyRelocatable<Expr_>{
|
||||
constexpr static bool value = true;
|
||||
};
|
||||
|
||||
struct Expr{
|
||||
int line = 0;
|
||||
virtual ~Expr() = default;
|
||||
virtual void emit_(CodeEmitContext* ctx) = 0;
|
||||
virtual bool is_literal() const { return false; }
|
||||
virtual bool is_json_object() const { return false; }
|
||||
virtual bool is_attrib() const { return false; }
|
||||
virtual bool is_compare() const { return false; }
|
||||
virtual int star_level() const { return 0; }
|
||||
virtual bool is_tuple() const { return false; }
|
||||
virtual bool is_name() const { return false; }
|
||||
bool is_starred() const { return star_level() > 0; }
|
||||
|
||||
// for OP_DELETE_XXX
|
||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// for OP_STORE_XXX
|
||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct CodeEmitContext{
|
||||
VM* vm;
|
||||
FuncDecl_ func; // optional
|
||||
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
||||
// some bugs on MSVC (error C2280) when using Expr_vector
|
||||
// so we use stack_no_copy instead
|
||||
stack_no_copy<Expr_> s_expr;
|
||||
int level;
|
||||
std::set<Str> global_names;
|
||||
CodeEmitContext(VM* vm, CodeObject_ co, int level): vm(vm), co(co), level(level) {}
|
||||
|
||||
int curr_block_i = 0;
|
||||
bool is_compiling_class = false;
|
||||
int base_stack_size = 0;
|
||||
|
||||
std::map<void*, int> _co_consts_nonstring_dedup_map;
|
||||
std::map<std::string, int, std::less<>> _co_consts_string_dedup_map;
|
||||
|
||||
int get_loop() const;
|
||||
CodeBlock* enter_block(CodeBlockType type);
|
||||
void exit_block();
|
||||
void emit_expr(); // clear the expression stack and generate bytecode
|
||||
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual=false);
|
||||
void revert_last_emit_();
|
||||
int emit_int(i64 value, int line);
|
||||
void patch_jump(int index);
|
||||
bool add_label(StrName name);
|
||||
int add_varname(StrName name);
|
||||
int add_const(PyVar);
|
||||
int add_const_string(std::string_view);
|
||||
int add_func_decl(FuncDecl_ decl);
|
||||
void emit_store_name(NameScope scope, StrName name, int line);
|
||||
void try_merge_for_iter_store(int);
|
||||
};
|
||||
|
||||
struct NameExpr: Expr{
|
||||
StrName name;
|
||||
NameScope scope;
|
||||
NameExpr(StrName name, NameScope scope): name(name), scope(scope) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
bool is_name() const override { return true; }
|
||||
};
|
||||
|
||||
struct InvertExpr: Expr{
|
||||
Expr_ child;
|
||||
InvertExpr(Expr_&& child): child(std::move(child)) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct StarredExpr: Expr{
|
||||
int level;
|
||||
Expr_ child;
|
||||
StarredExpr(int level, Expr_&& child): level(level), child(std::move(child)) {}
|
||||
int star_level() const override { return level; }
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct NotExpr: Expr{
|
||||
Expr_ child;
|
||||
NotExpr(Expr_&& child): child(std::move(child)) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct AndExpr: Expr{
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct OrExpr: Expr{
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
// [None, True, False, ...]
|
||||
struct Literal0Expr: Expr{
|
||||
TokenIndex token;
|
||||
Literal0Expr(TokenIndex token): token(token) {}
|
||||
bool is_json_object() const override { return true; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct LongExpr: Expr{
|
||||
Str s;
|
||||
LongExpr(const Str& s): s(s) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct BytesExpr: Expr{
|
||||
Str s;
|
||||
BytesExpr(const Str& s): s(s) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct ImagExpr: Expr{
|
||||
f64 value;
|
||||
ImagExpr(f64 value): value(value) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
// @num, @str which needs to invoke OP_LOAD_CONST
|
||||
struct LiteralExpr: Expr{
|
||||
TokenValue value;
|
||||
LiteralExpr(TokenValue value): value(value) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool is_literal() const override { return true; }
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct NegatedExpr: Expr{
|
||||
Expr_ child;
|
||||
NegatedExpr(Expr_&& child): child(std::move(child)) {}
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool is_json_object() const override { return child->is_literal(); }
|
||||
};
|
||||
|
||||
struct SliceExpr: Expr{
|
||||
Expr_ start;
|
||||
Expr_ stop;
|
||||
Expr_ step;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct DictItemExpr: Expr{
|
||||
Expr_ key; // maybe nullptr if it is **kwargs
|
||||
Expr_ value;
|
||||
int star_level() const override { return value->star_level(); }
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct SequenceExpr: Expr{
|
||||
Expr_vector items;
|
||||
SequenceExpr(Expr_vector&& items): items(std::move(items)) {}
|
||||
virtual Opcode opcode() const = 0;
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override {
|
||||
for(auto& item: items) item->emit_(ctx);
|
||||
ctx->emit_(opcode(), items.size(), line);
|
||||
}
|
||||
};
|
||||
|
||||
struct ListExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
|
||||
return OP_BUILD_LIST;
|
||||
}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct DictExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
|
||||
return OP_BUILD_DICT;
|
||||
}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct SetExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_SET_UNPACK;
|
||||
return OP_BUILD_SET;
|
||||
}
|
||||
};
|
||||
|
||||
struct TupleExpr: SequenceExpr{
|
||||
using SequenceExpr::SequenceExpr;
|
||||
bool is_tuple() const override { return true; }
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
|
||||
return OP_BUILD_TUPLE;
|
||||
}
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct CompExpr: Expr{
|
||||
Expr_ expr; // loop expr
|
||||
Expr_ vars; // loop vars
|
||||
Expr_ iter; // loop iter
|
||||
Expr_ cond; // optional if condition
|
||||
|
||||
virtual Opcode op0() = 0;
|
||||
virtual Opcode op1() = 0;
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct ListCompExpr: CompExpr{
|
||||
Opcode op0() override { return OP_BUILD_LIST; }
|
||||
Opcode op1() override { return OP_LIST_APPEND; }
|
||||
};
|
||||
|
||||
struct DictCompExpr: CompExpr{
|
||||
Opcode op0() override { return OP_BUILD_DICT; }
|
||||
Opcode op1() override { return OP_DICT_ADD; }
|
||||
};
|
||||
|
||||
struct SetCompExpr: CompExpr{
|
||||
Opcode op0() override { return OP_BUILD_SET; }
|
||||
Opcode op1() override { return OP_SET_ADD; }
|
||||
};
|
||||
|
||||
struct LambdaExpr: Expr{
|
||||
FuncDecl_ decl;
|
||||
|
||||
LambdaExpr(FuncDecl_ decl): decl(decl) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override {
|
||||
int index = ctx->add_func_decl(decl);
|
||||
ctx->emit_(OP_LOAD_FUNCTION, index, line);
|
||||
}
|
||||
};
|
||||
|
||||
struct FStringExpr: Expr{
|
||||
Str src;
|
||||
FStringExpr(const Str& src): src(src) {}
|
||||
void _load_simple_expr(CodeEmitContext* ctx, Str expr);
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct SubscrExpr: Expr{
|
||||
Expr_ a;
|
||||
Expr_ b;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct AttribExpr: Expr{
|
||||
Expr_ a;
|
||||
StrName b;
|
||||
AttribExpr(Expr_ a, StrName b): a(std::move(a)), b(b) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
void emit_method(CodeEmitContext* ctx);
|
||||
bool is_attrib() const override { return true; }
|
||||
};
|
||||
|
||||
struct CallExpr: Expr{
|
||||
Expr_ callable;
|
||||
Expr_vector args;
|
||||
// **a will be interpreted as a special keyword argument: {"**": a}
|
||||
std::vector<std::pair<Str, Expr_>> kwargs;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct GroupedExpr: Expr{
|
||||
Expr_ a;
|
||||
GroupedExpr(Expr_&& a): a(std::move(a)) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override{
|
||||
a->emit_(ctx);
|
||||
}
|
||||
|
||||
bool emit_del(CodeEmitContext* ctx) override {
|
||||
return a->emit_del(ctx);
|
||||
}
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override {
|
||||
return a->emit_store(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
struct BinaryExpr: Expr{
|
||||
TokenIndex op;
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
bool is_compare() const override;
|
||||
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
|
||||
struct TernaryExpr: Expr{
|
||||
Expr_ cond;
|
||||
Expr_ true_expr;
|
||||
Expr_ false_expr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,170 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "codeobject.h"
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "obj.h"
|
||||
#include "vector.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
// weak reference fast locals
|
||||
struct FastLocals{
|
||||
// this is a weak reference
|
||||
const CodeObject* co;
|
||||
PyVar* a;
|
||||
|
||||
int size() const{ return co->varnames.size();}
|
||||
|
||||
PyVar& operator[](int i){ return a[i]; }
|
||||
PyVar operator[](int i) const { return a[i]; }
|
||||
|
||||
FastLocals(const CodeObject* co, PyVar* a): co(co), a(a) {}
|
||||
|
||||
PyVar* try_get_name(StrName name);
|
||||
NameDict_ to_namedict();
|
||||
|
||||
PyVar* begin() const { return a; }
|
||||
PyVar* end() const { return a + size(); }
|
||||
};
|
||||
|
||||
struct ValueStack {
|
||||
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
||||
PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE/128];
|
||||
PyVar* _sp;
|
||||
PyVar* _max_end;
|
||||
|
||||
static constexpr size_t max_size() { return PK_VM_STACK_SIZE; }
|
||||
|
||||
ValueStack(): _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {}
|
||||
|
||||
PyVar& top(){ return _sp[-1]; }
|
||||
PyVar top() const { return _sp[-1]; }
|
||||
PyVar& second(){ return _sp[-2]; }
|
||||
PyVar second() const { return _sp[-2]; }
|
||||
PyVar& third(){ return _sp[-3]; }
|
||||
PyVar third() const { return _sp[-3]; }
|
||||
PyVar& peek(int n){ return _sp[-n]; }
|
||||
PyVar peek(int n) const { return _sp[-n]; }
|
||||
void push(PyVar v){ *_sp++ = v; }
|
||||
void pop(){ --_sp; }
|
||||
PyVar popx(){ return *--_sp; }
|
||||
ArgsView view(int n){ return ArgsView(_sp-n, _sp); }
|
||||
void shrink(int n){ _sp -= n; }
|
||||
int size() const { return _sp - _begin; }
|
||||
bool empty() const { return _sp == _begin; }
|
||||
PyVar* begin() { return _begin; }
|
||||
PyVar* end() { return _sp; }
|
||||
void reset(PyVar* sp) { _sp = sp; }
|
||||
void clear() { _sp = _begin; }
|
||||
bool is_overflow() const { return _sp >= _max_end; }
|
||||
|
||||
PyVar operator[](int i) const { return _begin[i]; }
|
||||
PyVar& operator[](int i) { return _begin[i]; }
|
||||
|
||||
ValueStack(const ValueStack&) = delete;
|
||||
ValueStack(ValueStack&&) = delete;
|
||||
ValueStack& operator=(const ValueStack&) = delete;
|
||||
ValueStack& operator=(ValueStack&&) = delete;
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
int _ip;
|
||||
int _next_ip;
|
||||
// This is for unwinding only, use `actual_sp_base()` for value stack access
|
||||
PyVar* _sp_base;
|
||||
|
||||
const CodeObject* co;
|
||||
PyVar _module;
|
||||
PyVar _callable; // a function object or nullptr (global scope)
|
||||
FastLocals _locals;
|
||||
|
||||
NameDict& f_globals() { return _module->attr(); }
|
||||
PyVar f_closure_try_get(StrName name);
|
||||
|
||||
// function scope
|
||||
Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, PyVar* _locals_base)
|
||||
: _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base) { }
|
||||
|
||||
// exec/eval
|
||||
Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, FastLocals _locals)
|
||||
: _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
|
||||
|
||||
// global scope
|
||||
Frame(PyVar* p0, const CodeObject_& co, PyVar _module)
|
||||
: _ip(-1), _next_ip(0), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
|
||||
|
||||
int next_bytecode() {
|
||||
_ip = _next_ip++;
|
||||
PK_DEBUG_ASSERT(_ip >= 0 && _ip < co->codes.size());
|
||||
return _ip;
|
||||
}
|
||||
|
||||
PyVar* actual_sp_base() const { return _locals.a; }
|
||||
|
||||
int stack_size(ValueStack* _s) const { return _s->_sp - actual_sp_base(); }
|
||||
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
||||
|
||||
void jump_abs(int i){ _next_ip = i; }
|
||||
bool jump_to_exception_handler(ValueStack*);
|
||||
int _exit_block(ValueStack*, int);
|
||||
void jump_abs_break(ValueStack*, int);
|
||||
|
||||
void loop_break(ValueStack* s_data, const CodeObject*){
|
||||
jump_abs_break(s_data, co->_get_block_codei(_ip).end);
|
||||
}
|
||||
|
||||
int curr_lineno() const { return co->lines[_ip].lineno; }
|
||||
|
||||
void _gc_mark() const {
|
||||
PK_OBJ_MARK(_module);
|
||||
co->_gc_mark();
|
||||
// Frame could be stored in a generator, so mark _callable for safety
|
||||
if(_callable != nullptr) PK_OBJ_MARK(_callable);
|
||||
}
|
||||
};
|
||||
|
||||
struct LinkedFrame{
|
||||
LinkedFrame* f_back;
|
||||
Frame frame;
|
||||
template<typename... Args>
|
||||
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
struct CallStack{
|
||||
static_assert(sizeof(LinkedFrame) <= 64 && std::is_trivially_destructible_v<LinkedFrame>);
|
||||
|
||||
LinkedFrame* _tail;
|
||||
int _size;
|
||||
CallStack(): _tail(nullptr), _size(0) {}
|
||||
|
||||
int size() const { return _size; }
|
||||
bool empty() const { return _size == 0; }
|
||||
void clear(){ while(!empty()) pop(); }
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args){
|
||||
_tail = new(pool64_alloc<LinkedFrame>()) LinkedFrame(_tail, std::forward<Args>(args)...);
|
||||
++_size;
|
||||
}
|
||||
|
||||
void pop(){
|
||||
PK_DEBUG_ASSERT(!empty())
|
||||
LinkedFrame* p = _tail;
|
||||
_tail = p->f_back;
|
||||
pool64_dealloc(p);
|
||||
--_size;
|
||||
}
|
||||
|
||||
Frame& top() const {
|
||||
PK_DEBUG_ASSERT(!empty())
|
||||
return _tail->frame;
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void apply(Func&& f){
|
||||
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) f(p->frame);
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace pkpy
|
||||
@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "obj.h"
|
||||
#include "codeobject.h"
|
||||
#include "namedict.h"
|
||||
|
||||
namespace pkpy {
|
||||
struct ManagedHeap{
|
||||
std::vector<PyVar> _no_gc;
|
||||
std::vector<PyVar> gen;
|
||||
VM* vm;
|
||||
void (*_gc_on_delete)(VM*, PyVar) = nullptr;
|
||||
void (*_gc_marker_ex)(VM*) = nullptr;
|
||||
|
||||
ManagedHeap(VM* vm): vm(vm) {}
|
||||
|
||||
int gc_threshold = PK_GC_MIN_THRESHOLD;
|
||||
int gc_counter = 0;
|
||||
|
||||
/********************/
|
||||
int _gc_lock_counter = 0;
|
||||
struct ScopeLock{
|
||||
PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
|
||||
|
||||
ManagedHeap* heap;
|
||||
ScopeLock(ManagedHeap* heap): heap(heap){
|
||||
heap->_gc_lock_counter++;
|
||||
}
|
||||
~ScopeLock(){
|
||||
heap->_gc_lock_counter--;
|
||||
}
|
||||
};
|
||||
|
||||
ScopeLock gc_scope_lock(){
|
||||
return ScopeLock(this);
|
||||
}
|
||||
/********************/
|
||||
|
||||
template<typename T, typename... Args>
|
||||
PyVar gcnew(Type type, Args&&... args){
|
||||
using __T = Py_<std::decay_t<T>>;
|
||||
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
|
||||
PyVar obj = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
|
||||
gen.push_back(obj);
|
||||
gc_counter++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
PyVar _new(Type type, Args&&... args){
|
||||
using __T = Py_<std::decay_t<T>>;
|
||||
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
|
||||
PyVar obj = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
|
||||
obj->gc_enabled = false;
|
||||
_no_gc.push_back(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
#if PK_DEBUG_GC_STATS
|
||||
inline static std::map<Type, int> deleted;
|
||||
#endif
|
||||
|
||||
int sweep();
|
||||
void _auto_collect();
|
||||
bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
|
||||
int collect();
|
||||
void mark();
|
||||
~ManagedHeap();
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
4
include/pocketpy/interpreter/ceval.h
Normal file
4
include/pocketpy/interpreter/ceval.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
// dummy header for ceval.cpp
|
||||
67
include/pocketpy/interpreter/frame.h
Normal file
67
include/pocketpy/interpreter/frame.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name);
|
||||
NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co);
|
||||
|
||||
typedef struct ValueStack {
|
||||
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() ==
|
||||
// true`.
|
||||
py_TValue* sp;
|
||||
py_TValue* end;
|
||||
py_TValue begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
|
||||
} ValueStack;
|
||||
|
||||
void ValueStack__ctor(ValueStack* self);
|
||||
void ValueStack__clear(ValueStack* self);
|
||||
|
||||
typedef struct UnwindTarget {
|
||||
struct UnwindTarget* next;
|
||||
int iblock;
|
||||
int offset;
|
||||
} UnwindTarget;
|
||||
|
||||
UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset);
|
||||
void UnwindTarget__delete(UnwindTarget* self);
|
||||
|
||||
typedef struct Frame {
|
||||
struct Frame* f_back;
|
||||
const Bytecode* ip;
|
||||
const CodeObject* co;
|
||||
py_GlobalRef module;
|
||||
py_StackRef p0; // unwinding base
|
||||
py_StackRef locals; // locals base
|
||||
bool has_function; // is p0 a function?
|
||||
bool is_dynamic; // is dynamic frame?
|
||||
UnwindTarget* uw_list;
|
||||
} Frame;
|
||||
|
||||
Frame* Frame__new(const CodeObject* co,
|
||||
py_GlobalRef module,
|
||||
py_StackRef p0,
|
||||
py_StackRef locals,
|
||||
bool has_function);
|
||||
void Frame__delete(Frame* self);
|
||||
|
||||
int Frame__ip(const Frame* self);
|
||||
int Frame__lineno(const Frame* self);
|
||||
int Frame__iblock(const Frame* self);
|
||||
py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name);
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name);
|
||||
|
||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*);
|
||||
void Frame__prepare_jump_break(Frame* self, ValueStack*, int);
|
||||
int Frame__prepare_loop_break(Frame* self, ValueStack*);
|
||||
int Frame__exit_block(Frame* self, ValueStack*, int);
|
||||
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock);
|
||||
void Frame__set_unwind_target(Frame* self, py_TValue* sp);
|
||||
|
||||
void Frame__gc_mark(Frame* self);
|
||||
26
include/pocketpy/interpreter/gc.h
Normal file
26
include/pocketpy/interpreter/gc.h
Normal file
@ -0,0 +1,26 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/config.h"
|
||||
|
||||
typedef struct ManagedHeap{
|
||||
c11_vector no_gc;
|
||||
c11_vector gen;
|
||||
|
||||
int gc_threshold;
|
||||
int gc_counter;
|
||||
VM* vm;
|
||||
|
||||
void (*gc_on_delete)(VM*, PyObject*);
|
||||
} ManagedHeap;
|
||||
|
||||
void ManagedHeap__ctor(ManagedHeap* self, VM* vm);
|
||||
void ManagedHeap__dtor(ManagedHeap* self);
|
||||
|
||||
void ManagedHeap__collect_if_needed(ManagedHeap* self);
|
||||
int ManagedHeap__collect(ManagedHeap* self);
|
||||
int ManagedHeap__sweep(ManagedHeap* self);
|
||||
|
||||
PyObject* ManagedHeap__new(ManagedHeap* self, py_Type type, int slots, int udsize);
|
||||
PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize);
|
||||
|
||||
// external implementation
|
||||
void ManagedHeap__mark(ManagedHeap* self);
|
||||
13
include/pocketpy/interpreter/generator.h
Normal file
13
include/pocketpy/interpreter/generator.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
typedef struct Generator{
|
||||
Frame* frame;
|
||||
int state;
|
||||
} Generator;
|
||||
|
||||
void pk_newgenerator(py_Ref out, Frame* frame, py_TValue* backup, int backup_length);
|
||||
|
||||
void Generator__dtor(Generator* ud);
|
||||
10
include/pocketpy/interpreter/modules.h
Normal file
10
include/pocketpy/interpreter/modules.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
void pk__add_module_pkpy();
|
||||
void pk__add_module_os();
|
||||
void pk__add_module_sys();
|
||||
void pk__add_module_math();
|
||||
void pk__add_module_dis();
|
||||
void pk__add_module_random();
|
||||
void pk__add_module_json();
|
||||
void pk__add_module_gc();
|
||||
146
include/pocketpy/interpreter/vm.h
Normal file
146
include/pocketpy/interpreter/vm.h
Normal file
@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/gc.h"
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/interpreter/modules.h"
|
||||
|
||||
// TODO:
|
||||
// 1. __eq__ and __ne__ fallbacks
|
||||
// 2. un-cleared exception detection
|
||||
// 3. super()
|
||||
|
||||
typedef struct py_TypeInfo {
|
||||
py_Name name;
|
||||
py_Type base;
|
||||
|
||||
py_TValue self;
|
||||
py_TValue module; // the module where the type is defined
|
||||
|
||||
bool is_python; // is it a python class? (not derived from c object)
|
||||
bool is_sealed; // can it be subclassed?
|
||||
|
||||
void (*dtor)(void*);
|
||||
|
||||
c11_vector /*T=py_Name*/ annotated_fields;
|
||||
|
||||
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
|
||||
void (*gc_mark)(void* ud);
|
||||
|
||||
/* Magic Slots */
|
||||
py_TValue magic[64];
|
||||
} py_TypeInfo;
|
||||
|
||||
typedef struct VM {
|
||||
Frame* top_frame;
|
||||
|
||||
ModuleDict modules;
|
||||
c11_vector /*T=py_TypeInfo*/ types;
|
||||
|
||||
py_TValue builtins; // builtins module
|
||||
py_TValue main; // __main__ module
|
||||
|
||||
void (*ceval_on_step)(Frame*, Bytecode);
|
||||
char* (*import_file)(const char*);
|
||||
void (*print)(const char*);
|
||||
|
||||
py_TValue last_retval;
|
||||
py_TValue curr_exception;
|
||||
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
|
||||
bool is_stopiteration;
|
||||
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
py_TValue* __curr_class;
|
||||
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
ManagedHeap heap;
|
||||
ValueStack stack; // put `stack` at the end for better cache locality
|
||||
} VM;
|
||||
|
||||
void VM__ctor(VM* self);
|
||||
void VM__dtor(VM* self);
|
||||
|
||||
void VM__push_frame(VM* self, Frame* frame);
|
||||
void VM__pop_frame(VM* self);
|
||||
|
||||
bool pk__parse_int_slice(py_Ref slice, int length, int* start, int* stop, int* step);
|
||||
bool pk__normalize_index(int* index, int length);
|
||||
|
||||
void pk__mark_value(py_TValue*);
|
||||
void pk__mark_namedict(NameDict*);
|
||||
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*));
|
||||
|
||||
bool pk_wrapper__self(int argc, py_Ref argv);
|
||||
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv);
|
||||
|
||||
typedef enum FrameResult {
|
||||
RES_RETURN,
|
||||
RES_CALL,
|
||||
RES_YIELD,
|
||||
RES_ERROR,
|
||||
} FrameResult;
|
||||
|
||||
FrameResult VM__run_top_frame(VM* self);
|
||||
|
||||
py_Type pk_newtype(const char* name,
|
||||
py_Type base,
|
||||
const py_GlobalRef module,
|
||||
void (*dtor)(void*),
|
||||
bool is_python,
|
||||
bool is_sealed);
|
||||
|
||||
FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
|
||||
|
||||
const char* pk_opname(Opcode op);
|
||||
|
||||
int pk_arrayview(py_Ref self, py_TValue** p);
|
||||
bool pk_wrapper__arrayequal(py_Type type, int argc, py_Ref argv);
|
||||
bool pk_arrayiter(py_Ref val);
|
||||
bool pk_arraycontains(py_Ref self, py_Ref val);
|
||||
|
||||
bool pk_loadmethod(py_StackRef self, py_Name name);
|
||||
bool pk_callmagic(py_Name name, int argc, py_Ref argv);
|
||||
|
||||
bool pk_exec(CodeObject* co, py_Ref module);
|
||||
|
||||
/// Assumes [a, b] are on the stack, performs a binary op.
|
||||
/// The result is stored in `self->last_retval`.
|
||||
/// The stack remains unchanged.
|
||||
bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop);
|
||||
|
||||
void pk_print_stack(VM* self, Frame* frame, Bytecode byte);
|
||||
|
||||
// type registration
|
||||
void pk_object__register();
|
||||
void pk_number__register();
|
||||
py_Type pk_str__register();
|
||||
py_Type pk_str_iterator__register();
|
||||
py_Type pk_bytes__register();
|
||||
py_Type pk_dict__register();
|
||||
py_Type pk_dict_items__register();
|
||||
py_Type pk_list__register();
|
||||
py_Type pk_tuple__register();
|
||||
py_Type pk_array_iterator__register();
|
||||
py_Type pk_slice__register();
|
||||
py_Type pk_function__register();
|
||||
py_Type pk_nativefunc__register();
|
||||
py_Type pk_range__register();
|
||||
py_Type pk_range_iterator__register();
|
||||
py_Type pk_BaseException__register();
|
||||
py_Type pk_Exception__register();
|
||||
py_Type pk_super__register();
|
||||
py_Type pk_property__register();
|
||||
py_Type pk_staticmethod__register();
|
||||
py_Type pk_classmethod__register();
|
||||
py_Type pk_generator__register();
|
||||
py_Type pk_namedict__register();
|
||||
py_Type pk_locals__register();
|
||||
py_Type pk_code__register();
|
||||
|
||||
py_TValue pk_builtins__register();
|
||||
|
||||
/* mappingproxy */
|
||||
void pk_mappingproxy__namedict(py_Ref out, py_Ref object);
|
||||
void pk_mappingproxy__locals(py_Ref out, Frame* frame);
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy{
|
||||
unsigned char* _default_import_handler(const char*, int*);
|
||||
void add_module_os(VM* vm);
|
||||
void add_module_io(VM* vm);
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "cffi.h"
|
||||
#include "common.h"
|
||||
#include "frame.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
struct RangeIter{
|
||||
Range r;
|
||||
i64 current;
|
||||
RangeIter(Range r) : r(r), current(r.start) {}
|
||||
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
struct ArrayIter{
|
||||
PyVar ref;
|
||||
PyVar* begin;
|
||||
PyVar* end;
|
||||
PyVar* current;
|
||||
|
||||
ArrayIter(PyVar ref, PyVar* begin, PyVar* end)
|
||||
: ref(ref), begin(begin), end(end), current(begin) {}
|
||||
|
||||
void _gc_mark() const{ PK_OBJ_MARK(ref); }
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
struct StringIter{
|
||||
PyVar ref;
|
||||
int i; // byte index
|
||||
StringIter(PyVar ref) : ref(ref), i(0) {}
|
||||
void _gc_mark() const{ PK_OBJ_MARK(ref); }
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
struct Generator{
|
||||
Frame frame;
|
||||
int state; // 0,1,2
|
||||
List s_backup;
|
||||
|
||||
Generator(Frame&& frame, ArgsView buffer): frame(std::move(frame)), state(0) {
|
||||
for(PyVar obj: buffer) s_backup.push_back(obj);
|
||||
}
|
||||
|
||||
void _gc_mark() const{
|
||||
frame._gc_mark();
|
||||
for(PyVar obj: s_backup) PK_OBJ_MARK(obj);
|
||||
}
|
||||
|
||||
PyVar next(VM* vm);
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
struct DictItemsIter{
|
||||
PyVar ref;
|
||||
int i;
|
||||
DictItemsIter(PyVar ref) : ref(ref) {
|
||||
i = PK_OBJ_GET(Dict, ref)._head_idx;
|
||||
}
|
||||
void _gc_mark() const{ PK_OBJ_MARK(ref); }
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,144 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "error.h"
|
||||
#include "str.h"
|
||||
#include "obj.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
typedef uint8_t TokenIndex;
|
||||
|
||||
constexpr const char* kTokens[] = {
|
||||
"is not", "not in", "yield from",
|
||||
"@eof", "@eol", "@sof",
|
||||
"@id", "@num", "@str", "@fstr", "@long", "@bytes", "@imag",
|
||||
"@indent", "@dedent",
|
||||
/*****************************************/
|
||||
"+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed
|
||||
"*", "*=", "/", "/=", "//", "//=", "%", "%=",
|
||||
"&", "&=", "|", "|=", "^", "^=",
|
||||
"<<", "<<=", ">>", ">>=",
|
||||
/*****************************************/
|
||||
".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}",
|
||||
"**", "=", ">", "<", "..", "...", "->", "@", "==", "!=", ">=", "<=",
|
||||
"++", "--", "~",
|
||||
/** KW_BEGIN **/
|
||||
"class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield",
|
||||
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
|
||||
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
|
||||
};
|
||||
|
||||
using TokenValue = std::variant<std::monostate, i64, f64, Str>;
|
||||
const TokenIndex kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
|
||||
|
||||
constexpr TokenIndex TK(const char token[]) {
|
||||
for(int k=0; k<kTokenCount; k++){
|
||||
const char* i = kTokens[k];
|
||||
const char* j = token;
|
||||
while(*i && *j && *i == *j) { i++; j++;}
|
||||
if(*i == *j) return k;
|
||||
}
|
||||
return 255;
|
||||
}
|
||||
|
||||
inline constexpr bool is_raw_string_used(TokenIndex t){
|
||||
return t == TK("@id") || t == TK("@long");
|
||||
}
|
||||
|
||||
#define TK_STR(t) kTokens[t]
|
||||
const std::map<std::string_view, TokenIndex> kTokenKwMap = [](){
|
||||
std::map<std::string_view, TokenIndex> map;
|
||||
for(int k=TK("class"); k<kTokenCount; k++) map[kTokens[k]] = k;
|
||||
return map;
|
||||
}();
|
||||
|
||||
struct Token{
|
||||
TokenIndex type;
|
||||
const char* start;
|
||||
int length;
|
||||
int line;
|
||||
int brackets_level;
|
||||
TokenValue value;
|
||||
|
||||
Str str() const { return Str(start, length);}
|
||||
std::string_view sv() const { return std::string_view(start, length);}
|
||||
};
|
||||
|
||||
// https://docs.python.org/3/reference/expressions.html#operator-precedence
|
||||
enum Precedence {
|
||||
PREC_LOWEST,
|
||||
PREC_LAMBDA, // lambda
|
||||
PREC_TERNARY, // ?:
|
||||
PREC_LOGICAL_OR, // or
|
||||
PREC_LOGICAL_AND, // and
|
||||
PREC_LOGICAL_NOT, // not
|
||||
/* https://docs.python.org/3/reference/expressions.html#comparisons
|
||||
* Unlike C, all comparison operations in Python have the same priority,
|
||||
* which is lower than that of any arithmetic, shifting or bitwise operation.
|
||||
* Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics.
|
||||
*/
|
||||
PREC_COMPARISION, // < > <= >= != ==, in / is / is not / not in
|
||||
PREC_BITWISE_OR, // |
|
||||
PREC_BITWISE_XOR, // ^
|
||||
PREC_BITWISE_AND, // &
|
||||
PREC_BITWISE_SHIFT, // << >>
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / % // @
|
||||
PREC_UNARY, // - not ~
|
||||
PREC_EXPONENT, // **
|
||||
PREC_PRIMARY, // f() x[] a.b 1:2
|
||||
PREC_HIGHEST,
|
||||
};
|
||||
|
||||
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
|
||||
|
||||
struct Lexer {
|
||||
VM* vm;
|
||||
std::shared_ptr<SourceData> src;
|
||||
const char* token_start;
|
||||
const char* curr_char;
|
||||
int current_line = 1;
|
||||
std::vector<Token> nexts;
|
||||
stack_no_copy<int, small_vector_2<int, 8>> indents;
|
||||
int brackets_level = 0;
|
||||
|
||||
char peekchar() const{ return *curr_char; }
|
||||
bool match_n_chars(int n, char c0);
|
||||
bool match_string(const char* s);
|
||||
int eat_spaces();
|
||||
|
||||
bool eat_indentation();
|
||||
char eatchar();
|
||||
char eatchar_include_newline();
|
||||
int eat_name();
|
||||
void skip_line_comment();
|
||||
bool matchchar(char c);
|
||||
void add_token(TokenIndex type, TokenValue value={});
|
||||
void add_token_2(char c, TokenIndex one, TokenIndex two);
|
||||
Str eat_string_until(char quote, bool raw);
|
||||
void eat_string(char quote, StringType type);
|
||||
|
||||
void eat_number();
|
||||
bool lex_one_token();
|
||||
|
||||
/***** Error Reporter *****/
|
||||
void throw_err(StrName type, Str msg);
|
||||
void throw_err(StrName type, Str msg, int lineno, const char* cursor);
|
||||
void SyntaxError(Str msg){ throw_err("SyntaxError", msg); }
|
||||
void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); }
|
||||
void IndentationError(Str msg){ throw_err("IndentationError", msg); }
|
||||
Lexer(VM* vm, std::shared_ptr<SourceData> src);
|
||||
std::vector<Token> run();
|
||||
};
|
||||
|
||||
|
||||
enum class IntParsingResult{
|
||||
Success,
|
||||
Failure,
|
||||
Overflow,
|
||||
};
|
||||
|
||||
IntParsingResult parse_uint(std::string_view text, i64* out, int base);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,132 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
inline bool isclose(float a, float b){ return std::fabs(a - b) < 1e-4; }
|
||||
|
||||
struct Vec2{
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
|
||||
float x, y;
|
||||
Vec2() : x(0.0f), y(0.0f) {}
|
||||
Vec2(float x, float y) : x(x), y(y) {}
|
||||
|
||||
Vec2 operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
|
||||
Vec2 operator-(const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
|
||||
Vec2 operator*(float s) const { return Vec2(x * s, y * s); }
|
||||
Vec2 operator*(const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
|
||||
Vec2 operator/(float s) const { return Vec2(x / s, y / s); }
|
||||
Vec2 operator-() const { return Vec2(-x, -y); }
|
||||
bool operator==(const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); }
|
||||
bool operator!=(const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
|
||||
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
|
||||
float cross(const Vec2& v) const { return x * v.y - y * v.x; }
|
||||
float length() const { return sqrtf(x * x + y * y); }
|
||||
float length_squared() const { return x * x + y * y; }
|
||||
Vec2 normalize() const { float l = length(); return Vec2(x / l, y / l); }
|
||||
Vec2 rotate(float radian) const { float cr = cosf(radian), sr = sinf(radian); return Vec2(x * cr - y * sr, x * sr + y * cr); }
|
||||
NoReturn normalize_() { float l = length(); x /= l; y /= l; return {}; }
|
||||
NoReturn copy_(const Vec2& v) { x = v.x; y = v.y; return {}; }
|
||||
};
|
||||
|
||||
struct Vec3{
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
|
||||
float x, y, z;
|
||||
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||
|
||||
Vec3 operator+(const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); }
|
||||
Vec3 operator-(const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
|
||||
Vec3 operator*(float s) const { return Vec3(x * s, y * s, z * s); }
|
||||
Vec3 operator*(const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
|
||||
Vec3 operator/(float s) const { return Vec3(x / s, y / s, z / s); }
|
||||
Vec3 operator-() const { return Vec3(-x, -y, -z); }
|
||||
bool operator==(const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); }
|
||||
bool operator!=(const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
|
||||
float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; }
|
||||
Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
|
||||
float length() const { return sqrtf(x * x + y * y + z * z); }
|
||||
float length_squared() const { return x * x + y * y + z * z; }
|
||||
Vec3 normalize() const { float l = length(); return Vec3(x / l, y / l, z / l); }
|
||||
NoReturn normalize_() { float l = length(); x /= l; y /= l; z /= l; return {}; }
|
||||
NoReturn copy_(const Vec3& v) { x = v.x; y = v.y; z = v.z; return {}; }
|
||||
};
|
||||
|
||||
struct Vec4{
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
|
||||
float x, y, z, w;
|
||||
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
|
||||
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||
|
||||
Vec4 operator+(const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
|
||||
Vec4 operator-(const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
|
||||
Vec4 operator*(float s) const { return Vec4(x * s, y * s, z * s, w * s); }
|
||||
Vec4 operator*(const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
|
||||
Vec4 operator/(float s) const { return Vec4(x / s, y / s, z / s, w / s); }
|
||||
Vec4 operator-() const { return Vec4(-x, -y, -z, -w); }
|
||||
bool operator==(const Vec4& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w); }
|
||||
bool operator!=(const Vec4& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w); }
|
||||
float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; }
|
||||
float length() const { return sqrtf(x * x + y * y + z * z + w * w); }
|
||||
float length_squared() const { return x * x + y * y + z * z + w * w; }
|
||||
Vec4 normalize() const { float l = length(); return Vec4(x / l, y / l, z / l, w / l); }
|
||||
NoReturn normalize_() { float l = length(); x /= l; y /= l; z /= l; w /= l; return {}; }
|
||||
NoReturn copy_(const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; return {}; }
|
||||
};
|
||||
|
||||
struct Mat3x3{
|
||||
static void _register(VM* vm, PyVar mod, PyVar type);
|
||||
|
||||
union {
|
||||
struct {
|
||||
float _11, _12, _13;
|
||||
float _21, _22, _23;
|
||||
float _31, _32, _33;
|
||||
};
|
||||
float m[3][3];
|
||||
float v[9];
|
||||
};
|
||||
|
||||
Mat3x3();
|
||||
Mat3x3(float, float, float, float, float, float, float, float, float);
|
||||
|
||||
static Mat3x3 zeros();
|
||||
static Mat3x3 ones();
|
||||
static Mat3x3 identity();
|
||||
|
||||
Mat3x3 operator+(const Mat3x3& other) const;
|
||||
Mat3x3 operator-(const Mat3x3& other) const;
|
||||
Mat3x3 operator*(float scalar) const;
|
||||
Mat3x3 operator/(float scalar) const;
|
||||
|
||||
bool operator==(const Mat3x3& other) const;
|
||||
bool operator!=(const Mat3x3& other) const;
|
||||
|
||||
Mat3x3 matmul(const Mat3x3& other) const;
|
||||
Vec3 matmul(const Vec3& other) const;
|
||||
|
||||
float determinant() const;
|
||||
Mat3x3 transpose() const;
|
||||
bool inverse(Mat3x3& out) const;
|
||||
|
||||
/*************** affine transformations ***************/
|
||||
static Mat3x3 trs(Vec2 t, float radian, Vec2 s);
|
||||
bool is_affine() const;
|
||||
Vec2 _t() const;
|
||||
float _r() const;
|
||||
Vec2 _s() const;
|
||||
};
|
||||
|
||||
void add_module_linalg(VM* vm);
|
||||
|
||||
static_assert(sizeof(Py_<Mat3x3>) <= 64);
|
||||
static_assert(std::is_trivially_copyable<Vec2>::value);
|
||||
static_assert(std::is_trivially_copyable<Vec3>::value);
|
||||
static_assert(std::is_trivially_copyable<Vec4>::value);
|
||||
static_assert(std::is_trivially_copyable<Mat3x3>::value);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
void* pool64_alloc(size_t) noexcept;
|
||||
void pool64_dealloc(void*) noexcept;
|
||||
|
||||
void* pool128_alloc(size_t) noexcept;
|
||||
void pool128_dealloc(void*) noexcept;
|
||||
|
||||
template<typename T>
|
||||
void* pool64_alloc() noexcept{
|
||||
return pool64_alloc(sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void* pool128_alloc() noexcept{
|
||||
return pool128_alloc(sizeof(T));
|
||||
}
|
||||
|
||||
void pools_shrink_to_fit() noexcept;
|
||||
|
||||
std::string pool64_info() noexcept;
|
||||
std::string pool128_info() noexcept;
|
||||
|
||||
}; // namespace pkpy
|
||||
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
void add_module_time(VM* vm);
|
||||
void add_module_sys(VM* vm);
|
||||
void add_module_json(VM* vm);
|
||||
void add_module_math(VM* vm);
|
||||
void add_module_traceback(VM* vm);
|
||||
void add_module_dis(VM* vm);
|
||||
void add_module_gc(VM* vm);
|
||||
void add_module_line_profiler(VM* vm);
|
||||
void add_module_enum(VM* vm);
|
||||
void add_module___builtins(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,343 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "str.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
template<typename T>
|
||||
constexpr T default_invalid_value(){
|
||||
if constexpr(std::is_pointer_v<T>) return nullptr;
|
||||
else if constexpr(std::is_same_v<int, T>) return -1;
|
||||
else return Discarded();
|
||||
}
|
||||
|
||||
#define PK_SMALL_NAME_DICT_CAPACITY 8
|
||||
#define PK_SMALL_NAME_DICT_LOOP(B) for(int i=0; i<PK_SMALL_NAME_DICT_CAPACITY; i++) { B }
|
||||
|
||||
template<typename V>
|
||||
struct SmallNameDict{
|
||||
using K = StrName;
|
||||
static_assert(is_pod_v<V>);
|
||||
|
||||
bool _is_small;
|
||||
uint16_t _size;
|
||||
K _keys[PK_SMALL_NAME_DICT_CAPACITY];
|
||||
V _values[PK_SMALL_NAME_DICT_CAPACITY];
|
||||
|
||||
SmallNameDict(): _is_small(true), _size(0) {}
|
||||
|
||||
bool try_set(K key, V val){
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
if(_keys[i] == key){ _values[i] = val; return true; }
|
||||
)
|
||||
|
||||
if(_size == PK_SMALL_NAME_DICT_CAPACITY) return false;
|
||||
if(_keys[_size].empty()){
|
||||
_keys[_size] = key;
|
||||
_values[_size] = val;
|
||||
_size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
if(_keys[i].empty()){
|
||||
_keys[i] = key;
|
||||
_values[i] = val;
|
||||
_size++;
|
||||
return true;
|
||||
}
|
||||
)
|
||||
PK_UNREACHABLE()
|
||||
}
|
||||
|
||||
V try_get(K key) const {
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
if(_keys[i] == key) return _values[i];
|
||||
)
|
||||
return default_invalid_value<V>();
|
||||
}
|
||||
|
||||
V* try_get_2(K key) {
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
if(_keys[i] == key) return &_values[i];
|
||||
)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool del(K key){
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
if(_keys[i] == key){ _keys[i] = StrName(); _size--; return true; }
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void apply(Func func) const {
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
if(!_keys[i].empty()) func(_keys[i], _values[i]);
|
||||
)
|
||||
}
|
||||
|
||||
void clear(){
|
||||
PK_SMALL_NAME_DICT_LOOP(
|
||||
_keys[i] = StrName();
|
||||
)
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
uint16_t size() const { return _size; }
|
||||
uint16_t capacity() const { return PK_SMALL_NAME_DICT_CAPACITY; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct NameDictItem{
|
||||
StrName first;
|
||||
T second;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LargeNameDict {
|
||||
PK_ALWAYS_PASS_BY_POINTER(LargeNameDict)
|
||||
|
||||
using Item = NameDictItem<T>;
|
||||
static constexpr uint16_t kInitialCapacity = 32;
|
||||
static_assert(is_pod_v<T>);
|
||||
|
||||
bool _is_small;
|
||||
float _load_factor;
|
||||
uint16_t _size;
|
||||
|
||||
uint16_t _capacity;
|
||||
uint16_t _critical_size;
|
||||
uint16_t _mask;
|
||||
|
||||
Item* _items;
|
||||
|
||||
#define HASH_PROBE_1(key, ok, i) \
|
||||
ok = false; \
|
||||
i = key.index & _mask; \
|
||||
while(!_items[i].first.empty()) { \
|
||||
if(_items[i].first == (key)) { ok = true; break; } \
|
||||
i = (i + 1) & _mask; \
|
||||
}
|
||||
|
||||
#define HASH_PROBE_0 HASH_PROBE_1
|
||||
|
||||
LargeNameDict(float load_factor=PK_INST_ATTR_LOAD_FACTOR): _is_small(false), _load_factor(load_factor), _size(0) {
|
||||
_set_capacity_and_alloc_items(kInitialCapacity);
|
||||
}
|
||||
|
||||
~LargeNameDict(){ free(_items); }
|
||||
|
||||
uint16_t size() const { return _size; }
|
||||
uint16_t capacity() const { return _capacity; }
|
||||
|
||||
void _set_capacity_and_alloc_items(uint16_t val){
|
||||
_capacity = val;
|
||||
_critical_size = val * _load_factor;
|
||||
_mask = val - 1;
|
||||
|
||||
_items = (Item*)malloc(_capacity * sizeof(Item));
|
||||
memset(_items, 0, _capacity * sizeof(Item));
|
||||
}
|
||||
|
||||
void set(StrName key, T val){
|
||||
bool ok; uint16_t i;
|
||||
HASH_PROBE_1(key, ok, i);
|
||||
if(!ok) {
|
||||
_size++;
|
||||
if(_size > _critical_size){
|
||||
_rehash_2x();
|
||||
HASH_PROBE_1(key, ok, i);
|
||||
}
|
||||
_items[i].first = key;
|
||||
}
|
||||
_items[i].second = val;
|
||||
}
|
||||
|
||||
void _rehash_2x(){
|
||||
Item* old_items = _items;
|
||||
uint16_t old_capacity = _capacity;
|
||||
_set_capacity_and_alloc_items(_capacity * 2);
|
||||
for(uint16_t i=0; i<old_capacity; i++){
|
||||
if(old_items[i].first.empty()) continue;
|
||||
bool ok; uint16_t j;
|
||||
HASH_PROBE_1(old_items[i].first, ok, j);
|
||||
if(ok) PK_FATAL_ERROR();
|
||||
_items[j] = old_items[i];
|
||||
}
|
||||
free(old_items);
|
||||
}
|
||||
|
||||
T try_get(StrName key) const{
|
||||
bool ok; uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return default_invalid_value<T>();
|
||||
return _items[i].second;
|
||||
}
|
||||
|
||||
T* try_get_2(StrName key) {
|
||||
bool ok; uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return nullptr;
|
||||
return &_items[i].second;
|
||||
}
|
||||
|
||||
T try_get_likely_found(StrName key) const{
|
||||
uint16_t i = key.index & _mask;
|
||||
if(_items[i].first == key) return _items[i].second;
|
||||
i = (i + 1) & _mask;
|
||||
if(_items[i].first == key) return _items[i].second;
|
||||
return try_get(key);
|
||||
}
|
||||
|
||||
T* try_get_2_likely_found(StrName key) {
|
||||
uint16_t i = key.index & _mask;
|
||||
if(_items[i].first == key) return &_items[i].second;
|
||||
i = (i + 1) & _mask;
|
||||
if(_items[i].first == key) return &_items[i].second;
|
||||
return try_get_2(key);
|
||||
}
|
||||
|
||||
bool del(StrName key){
|
||||
bool ok; uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return false;
|
||||
_items[i].first = StrName();
|
||||
_items[i].second = nullptr;
|
||||
_size--;
|
||||
// tidy
|
||||
uint16_t pre_z = i;
|
||||
uint16_t z = (i + 1) & _mask;
|
||||
while(!_items[z].first.empty()){
|
||||
uint16_t h = _items[z].first.index & _mask;
|
||||
if(h != i) break;
|
||||
std::swap(_items[pre_z], _items[z]);
|
||||
pre_z = z;
|
||||
z = (z + 1) & _mask;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename __Func>
|
||||
void apply(__Func func) const {
|
||||
for(uint16_t i=0; i<_capacity; i++){
|
||||
if(_items[i].first.empty()) continue;
|
||||
func(_items[i].first, _items[i].second);
|
||||
}
|
||||
}
|
||||
|
||||
pod_vector<StrName> keys() const {
|
||||
pod_vector<StrName> v;
|
||||
for(uint16_t i=0; i<_capacity; i++){
|
||||
if(_items[i].first.empty()) continue;
|
||||
v.push_back(_items[i].first);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
for(uint16_t i=0; i<_capacity; i++){
|
||||
_items[i].first = StrName();
|
||||
_items[i].second = nullptr;
|
||||
}
|
||||
_size = 0;
|
||||
}
|
||||
#undef HASH_PROBE_0
|
||||
#undef HASH_PROBE_1
|
||||
};
|
||||
|
||||
template<typename V>
|
||||
struct NameDictImpl{
|
||||
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
|
||||
|
||||
union{
|
||||
SmallNameDict<V> _small;
|
||||
LargeNameDict<V> _large;
|
||||
};
|
||||
|
||||
NameDictImpl(): _small() {}
|
||||
NameDictImpl(float load_factor): _large(load_factor) {}
|
||||
|
||||
bool is_small() const{
|
||||
const bool* p = reinterpret_cast<const bool*>(this);
|
||||
return *p;
|
||||
}
|
||||
|
||||
void set(StrName key, V val){
|
||||
if(is_small()){
|
||||
bool ok = _small.try_set(key, val);
|
||||
if(!ok){
|
||||
SmallNameDict<V> copied(_small);
|
||||
// move to large name dict
|
||||
new (&_large) LargeNameDict<V>();
|
||||
copied.apply([&](StrName key, V val){
|
||||
_large.set(key, val);
|
||||
});
|
||||
_large.set(key, val);
|
||||
}
|
||||
}else{
|
||||
_large.set(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t size() const{ return is_small() ?_small.size() : _large.size(); }
|
||||
uint16_t capacity() const{ return is_small() ?_small.capacity() : _large.capacity(); }
|
||||
V try_get(StrName key) const { return is_small() ?_small.try_get(key) : _large.try_get(key); }
|
||||
V* try_get_2(StrName key) { return is_small() ?_small.try_get_2(key) : _large.try_get_2(key); }
|
||||
bool del(StrName key){ return is_small() ?_small.del(key) : _large.del(key); }
|
||||
|
||||
V try_get_likely_found(StrName key) const { return is_small() ?_small.try_get(key) : _large.try_get_likely_found(key); }
|
||||
V* try_get_2_likely_found(StrName key) { return is_small() ?_small.try_get_2(key) : _large.try_get_2_likely_found(key); }
|
||||
|
||||
bool contains(StrName key) const { return try_get(key) != default_invalid_value<V>(); }
|
||||
|
||||
V operator[](StrName key) const {
|
||||
V val = try_get_likely_found(key);
|
||||
if(val == default_invalid_value<V>()){
|
||||
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
if(is_small()) _small.clear();
|
||||
else _large.clear();
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void apply(Func func) const {
|
||||
if(is_small()) _small.apply(func);
|
||||
else _large.apply(func);
|
||||
}
|
||||
|
||||
pod_vector<StrName> keys() const{
|
||||
pod_vector<StrName> v;
|
||||
apply([&](StrName key, V val){
|
||||
v.push_back(key);
|
||||
});
|
||||
return v;
|
||||
}
|
||||
|
||||
pod_vector<NameDictItem<V>> items() const{
|
||||
pod_vector<NameDictItem<V>> v;
|
||||
apply([&](StrName key, V val){
|
||||
v.push_back(NameDictItem<V>{key, val});
|
||||
});
|
||||
return v;
|
||||
}
|
||||
|
||||
~NameDictImpl(){
|
||||
if(!is_small()) _large.~LargeNameDict<V>();
|
||||
}
|
||||
};
|
||||
|
||||
using NameDict = NameDictImpl<PyVar>;
|
||||
using NameDict_ = std::shared_ptr<NameDict>;
|
||||
using NameDictInt = NameDictImpl<int>;
|
||||
|
||||
static_assert(sizeof(NameDict) <= 128);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,336 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "namedict.h"
|
||||
#include "tuplelist.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Frame;
|
||||
class VM;
|
||||
|
||||
#if PK_ENABLE_STD_FUNCTION
|
||||
using NativeFuncC = std::function<PyVar(VM*, ArgsView)>;
|
||||
#else
|
||||
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
||||
#endif
|
||||
|
||||
enum class BindType{
|
||||
DEFAULT,
|
||||
STATICMETHOD,
|
||||
CLASSMETHOD,
|
||||
};
|
||||
|
||||
struct BoundMethod {
|
||||
PyVar self;
|
||||
PyVar func;
|
||||
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
|
||||
};
|
||||
|
||||
struct StaticMethod{
|
||||
PyVar func;
|
||||
StaticMethod(PyVar func) : func(func) {}
|
||||
};
|
||||
|
||||
struct ClassMethod{
|
||||
PyVar func;
|
||||
ClassMethod(PyVar func) : func(func) {}
|
||||
};
|
||||
|
||||
struct Property{
|
||||
PyVar getter;
|
||||
PyVar setter;
|
||||
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
|
||||
};
|
||||
|
||||
struct Range {
|
||||
i64 start = 0;
|
||||
i64 stop = -1;
|
||||
i64 step = 1;
|
||||
};
|
||||
|
||||
struct StarWrapper{
|
||||
int level; // either 1 or 2
|
||||
PyVar obj;
|
||||
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
|
||||
};
|
||||
|
||||
struct Bytes{
|
||||
unsigned char* _data;
|
||||
int _size;
|
||||
|
||||
int size() const noexcept { return _size; }
|
||||
int operator[](int i) const noexcept { return (int)_data[i]; }
|
||||
const unsigned char* data() const noexcept { return _data; }
|
||||
|
||||
bool operator==(const Bytes& rhs) const;
|
||||
bool operator!=(const Bytes& rhs) const;
|
||||
|
||||
Str str() const noexcept { return Str((char*)_data, _size); }
|
||||
std::string_view sv() const noexcept { return std::string_view((char*)_data, _size); }
|
||||
|
||||
Bytes() : _data(nullptr), _size(0) {}
|
||||
Bytes(unsigned char* p, int size): _data(p), _size(size) {}
|
||||
Bytes(const Str& str): Bytes(str.sv()) {}
|
||||
operator bool() const noexcept { return _data != nullptr; }
|
||||
|
||||
Bytes(std::string_view sv);
|
||||
Bytes(const Bytes& rhs);
|
||||
Bytes(Bytes&& rhs) noexcept;
|
||||
Bytes& operator=(Bytes&& rhs) noexcept;
|
||||
Bytes& operator=(const Bytes& rhs) = delete;
|
||||
std::pair<unsigned char*, int> detach() noexcept;
|
||||
|
||||
~Bytes(){ delete[] _data;}
|
||||
};
|
||||
|
||||
using Super = std::pair<PyVar, Type>;
|
||||
|
||||
struct Slice {
|
||||
PyVar start;
|
||||
PyVar stop;
|
||||
PyVar step;
|
||||
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
|
||||
};
|
||||
|
||||
struct PyObject{
|
||||
bool gc_enabled; // whether this object is managed by GC
|
||||
bool gc_marked; // whether this object is marked
|
||||
Type type;
|
||||
NameDict* _attr;
|
||||
|
||||
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||
|
||||
NameDict& attr() {
|
||||
PK_DEBUG_ASSERT(is_attr_valid())
|
||||
return *_attr;
|
||||
}
|
||||
|
||||
PyVar attr(StrName name) const {
|
||||
PK_DEBUG_ASSERT(is_attr_valid())
|
||||
return (*_attr)[name];
|
||||
}
|
||||
|
||||
virtual void _obj_gc_mark() = 0;
|
||||
virtual ~PyObject();
|
||||
|
||||
PyObject(Type type) : gc_enabled(true), gc_marked(false), type(type), _attr(nullptr) {}
|
||||
|
||||
void _enable_instance_dict() {
|
||||
_attr = new(pool128_alloc<NameDict>()) NameDict();
|
||||
}
|
||||
|
||||
void _enable_instance_dict(float lf){
|
||||
_attr = new(pool128_alloc<NameDict>()) NameDict(lf);
|
||||
}
|
||||
};
|
||||
|
||||
const int kTpIntIndex = 2;
|
||||
const int kTpFloatIndex = 3;
|
||||
|
||||
inline bool is_tagged(PyVar p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; }
|
||||
inline bool is_small_int(PyVar p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
|
||||
inline bool is_heap_int(PyVar p) noexcept { return !is_tagged(p) && p->type.index == kTpIntIndex; }
|
||||
inline bool is_float(PyVar p) noexcept { return !is_tagged(p) && p->type.index == kTpFloatIndex; }
|
||||
inline bool is_int(PyVar p) noexcept { return is_small_int(p) || is_heap_int(p); }
|
||||
|
||||
inline bool is_type(PyVar obj, Type type) {
|
||||
PK_DEBUG_ASSERT(obj != nullptr)
|
||||
return is_small_int(obj) ? type.index == kTpIntIndex : obj->type == type;
|
||||
}
|
||||
|
||||
template <typename, typename=void> struct has_gc_marker : std::false_type {};
|
||||
template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct Py_ final: PyObject {
|
||||
static_assert(!std::is_reference_v<T>, "T must not be a reference type. Are you using `PK_OBJ_GET(T&, ...)`?");
|
||||
|
||||
T _value;
|
||||
void _obj_gc_mark() override {
|
||||
if constexpr (has_gc_marker<T>::value) {
|
||||
_value._gc_mark();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Py_(Type type, Args&&... args) : PyObject(type), _value(std::forward<Args>(args)...) { }
|
||||
};
|
||||
|
||||
struct MappingProxy{
|
||||
PyVar obj;
|
||||
MappingProxy(PyVar obj) : obj(obj) {}
|
||||
NameDict& attr() { return obj->attr(); }
|
||||
};
|
||||
|
||||
void _gc_mark_namedict(NameDict*);
|
||||
StrName _type_name(VM* vm, Type type);
|
||||
template<typename T> T to_void_p(VM*, PyVar);
|
||||
PyVar from_void_p(VM*, void*);
|
||||
|
||||
|
||||
#define PK_OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
|
||||
|
||||
#define PK_OBJ_MARK(obj) \
|
||||
if(!is_tagged(obj) && !(obj)->gc_marked) { \
|
||||
(obj)->gc_marked = true; \
|
||||
(obj)->_obj_gc_mark(); \
|
||||
if((obj)->is_attr_valid()) _gc_mark_namedict((obj)->_attr); \
|
||||
}
|
||||
|
||||
#define VAR(x) py_var(vm, x)
|
||||
#define CAST(T, x) py_cast<T>(vm, x)
|
||||
#define _CAST(T, x) _py_cast<T>(vm, x)
|
||||
|
||||
#define CAST_F(x) py_cast<f64>(vm, x)
|
||||
#define CAST_DEFAULT(T, x, default_value) (x != vm->None) ? py_cast<T>(vm, x) : (default_value)
|
||||
|
||||
/*****************************************************************/
|
||||
template<>
|
||||
struct Py_<i64> final: PyObject {
|
||||
i64 _value;
|
||||
Py_(Type type, i64 val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {}
|
||||
};
|
||||
|
||||
inline bool try_cast_int(PyVar obj, i64* val) noexcept {
|
||||
if(is_small_int(obj)){
|
||||
*val = PK_BITS(obj) >> 2;
|
||||
return true;
|
||||
}else if(is_heap_int(obj)){
|
||||
*val = PK_OBJ_GET(i64, obj);
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
struct Py_<List> final: PyObject {
|
||||
List _value;
|
||||
Py_(Type type, List&& val): PyObject(type), _value(std::move(val)) {}
|
||||
Py_(Type type, const List& val): PyObject(type), _value(val) {}
|
||||
|
||||
void _obj_gc_mark() override {
|
||||
for(PyVar obj: _value) PK_OBJ_MARK(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Tuple> final: PyObject {
|
||||
Tuple _value;
|
||||
Py_(Type type, Tuple&& val): PyObject(type), _value(std::move(val)) {}
|
||||
Py_(Type type, const Tuple& val): PyObject(type), _value(val) {}
|
||||
|
||||
void _obj_gc_mark() override {
|
||||
for(PyVar obj: _value) PK_OBJ_MARK(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<MappingProxy> final: PyObject {
|
||||
MappingProxy _value;
|
||||
Py_(Type type, MappingProxy val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<BoundMethod> final: PyObject {
|
||||
BoundMethod _value;
|
||||
Py_(Type type, BoundMethod val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.self);
|
||||
PK_OBJ_MARK(_value.func);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<StarWrapper> final: PyObject {
|
||||
StarWrapper _value;
|
||||
Py_(Type type, StarWrapper val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<StaticMethod> final: PyObject {
|
||||
StaticMethod _value;
|
||||
Py_(Type type, StaticMethod val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.func);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<ClassMethod> final: PyObject {
|
||||
ClassMethod _value;
|
||||
Py_(Type type, ClassMethod val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.func);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Property> final: PyObject {
|
||||
Property _value;
|
||||
Py_(Type type, Property val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.getter);
|
||||
PK_OBJ_MARK(_value.setter);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Slice> final: PyObject {
|
||||
Slice _value;
|
||||
Py_(Type type, Slice val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.start);
|
||||
PK_OBJ_MARK(_value.stop);
|
||||
PK_OBJ_MARK(_value.step);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Super> final: PyObject {
|
||||
Super _value;
|
||||
template<typename... Args>
|
||||
Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.first);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<DummyInstance> final: PyObject {
|
||||
Py_(Type type): PyObject(type) {
|
||||
_enable_instance_dict();
|
||||
}
|
||||
void _obj_gc_mark() override {}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Type> final: PyObject {
|
||||
Type _value;
|
||||
Py_(Type type, Type val): PyObject(type), _value(val) {
|
||||
_enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
|
||||
}
|
||||
void _obj_gc_mark() override {}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<DummyModule> final: PyObject {
|
||||
Py_(Type type): PyObject(type) {
|
||||
_enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
|
||||
}
|
||||
void _obj_gc_mark() override {}
|
||||
};
|
||||
|
||||
extern PyVar const PY_NULL;
|
||||
extern PyVar const PY_OP_CALL;
|
||||
extern PyVar const PY_OP_YIELD;
|
||||
|
||||
} // namespace pkpy
|
||||
33
include/pocketpy/objects/base.h
Normal file
33
include/pocketpy/objects/base.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdlib.h"
|
||||
#include "assert.h"
|
||||
#include "string.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
typedef struct PyObject PyObject;
|
||||
typedef struct VM VM;
|
||||
extern VM* pk_current_vm;
|
||||
|
||||
typedef struct py_TValue {
|
||||
py_Type type;
|
||||
bool is_ptr;
|
||||
int extra;
|
||||
|
||||
union {
|
||||
int64_t _i64;
|
||||
double _f64;
|
||||
bool _bool;
|
||||
py_CFunction _cfunc;
|
||||
PyObject* _obj;
|
||||
// Vec2
|
||||
};
|
||||
} py_TValue;
|
||||
|
||||
// 16 bytes to make py_arg() macro work
|
||||
static_assert(sizeof(py_CFunction) <= 8, "sizeof(py_CFunction) > 8");
|
||||
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
|
||||
143
include/pocketpy/objects/codeobject.h
Normal file
143
include/pocketpy/objects/codeobject.h
Normal file
@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#define BC_NOARG 0
|
||||
#define BC_KEEPLINE -1
|
||||
|
||||
typedef enum FuncType {
|
||||
FuncType_UNSET,
|
||||
FuncType_NORMAL,
|
||||
FuncType_SIMPLE,
|
||||
FuncType_GENERATOR,
|
||||
} FuncType;
|
||||
|
||||
typedef enum NameScope {
|
||||
NAME_LOCAL,
|
||||
NAME_GLOBAL,
|
||||
NAME_GLOBAL_UNKNOWN,
|
||||
} NameScope;
|
||||
|
||||
typedef enum CodeBlockType {
|
||||
CodeBlockType_NO_BLOCK,
|
||||
CodeBlockType_FOR_LOOP,
|
||||
CodeBlockType_WHILE_LOOP,
|
||||
CodeBlockType_CONTEXT_MANAGER,
|
||||
CodeBlockType_TRY_EXCEPT,
|
||||
} CodeBlockType;
|
||||
|
||||
typedef enum Opcode {
|
||||
|
||||
#define OPCODE(name) OP_##name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
} Opcode;
|
||||
|
||||
typedef struct Bytecode {
|
||||
uint8_t op;
|
||||
uint16_t arg;
|
||||
} Bytecode;
|
||||
|
||||
void Bytecode__set_signed_arg(Bytecode* self, int arg);
|
||||
bool Bytecode__is_forward_jump(const Bytecode* self);
|
||||
|
||||
typedef struct CodeBlock {
|
||||
CodeBlockType type;
|
||||
int parent; // parent index in blocks
|
||||
int start; // start index of this block in codes, inclusive
|
||||
int end; // end index of this block in codes, exclusive
|
||||
int end2; // ...
|
||||
} CodeBlock;
|
||||
|
||||
typedef struct BytecodeEx {
|
||||
int lineno; // line number for each bytecode
|
||||
bool is_virtual; // whether this bytecode is virtual (not in source code)
|
||||
int iblock; // block index
|
||||
} BytecodeEx;
|
||||
|
||||
typedef struct CodeObject {
|
||||
SourceData_ src;
|
||||
c11_string* name;
|
||||
|
||||
c11_vector /*T=Bytecode*/ codes;
|
||||
c11_vector /*T=CodeObjectByteCodeEx*/ codes_ex;
|
||||
|
||||
c11_vector /*T=py_TValue*/ consts; // constants
|
||||
c11_vector /*T=py_Name*/ varnames; // local variables
|
||||
int nlocals; // cached varnames.size()
|
||||
|
||||
c11_smallmap_n2i varnames_inv;
|
||||
c11_smallmap_n2i labels;
|
||||
|
||||
c11_vector /*T=CodeBlock*/ blocks;
|
||||
c11_vector /*T=FuncDecl_*/ func_decls;
|
||||
|
||||
int start_line;
|
||||
int end_line;
|
||||
} CodeObject;
|
||||
|
||||
void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name);
|
||||
void CodeObject__dtor(CodeObject* self);
|
||||
int CodeObject__add_varname(CodeObject* self, py_Name name);
|
||||
void CodeObject__gc_mark(const CodeObject* self);
|
||||
|
||||
typedef struct FuncDeclKwArg {
|
||||
int index; // index in co->varnames
|
||||
uint16_t key; // name of this argument
|
||||
py_TValue value; // default value
|
||||
} FuncDeclKwArg;
|
||||
|
||||
typedef struct FuncDecl {
|
||||
RefCounted rc;
|
||||
CodeObject code; // strong ref
|
||||
|
||||
c11_vector /*T=int*/ args; // indices in co->varnames
|
||||
c11_vector /*T=KwArg*/ kwargs; // indices in co->varnames
|
||||
|
||||
int starred_arg; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg; // index in co->varnames, -1 if no **kwarg
|
||||
bool nested; // whether this function is nested
|
||||
|
||||
const char* docstring; // docstring of this function (weak ref)
|
||||
|
||||
FuncType type;
|
||||
c11_smallmap_n2i kw_to_index;
|
||||
} FuncDecl;
|
||||
|
||||
typedef FuncDecl* FuncDecl_;
|
||||
|
||||
FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name);
|
||||
bool FuncDecl__is_duplicated_arg(const FuncDecl* self, py_Name name);
|
||||
void FuncDecl__add_arg(FuncDecl* self, py_Name name);
|
||||
void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value);
|
||||
void FuncDecl__add_starred_arg(FuncDecl* self, py_Name name);
|
||||
void FuncDecl__add_starred_kwarg(FuncDecl* self, py_Name name);
|
||||
FuncDecl_ FuncDecl__build(c11_sv name,
|
||||
c11_sv* args,
|
||||
int argc,
|
||||
c11_sv starred_arg,
|
||||
c11_sv* kwargs,
|
||||
int kwargc,
|
||||
py_Ref kwdefaults, // a tuple contains default values
|
||||
c11_sv starred_kwarg,
|
||||
const char* docstring);
|
||||
|
||||
// runtime function
|
||||
typedef struct Function {
|
||||
FuncDecl_ decl;
|
||||
py_TValue module; // weak ref
|
||||
PyObject* clazz; // weak ref
|
||||
NameDict* closure; // strong ref
|
||||
py_CFunction cfunc; // wrapped C function
|
||||
} Function;
|
||||
|
||||
void Function__ctor(Function* self, FuncDecl_ decl, py_TValue* module);
|
||||
void Function__dtor(Function* self);
|
||||
18
include/pocketpy/objects/error.h
Normal file
18
include/pocketpy/objects/error.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
typedef struct{
|
||||
SourceData_ src;
|
||||
int lineno;
|
||||
char msg[100];
|
||||
} Error;
|
||||
|
||||
void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code);
|
||||
int py_BaseException__get_lineno(py_Ref, const CodeObject* code);
|
||||
void py_BaseException__stpush(py_Ref, SourceData_ src, int lineno, const char* func_name);
|
||||
27
include/pocketpy/objects/namedict.h
Normal file
27
include/pocketpy/objects/namedict.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K uint16_t
|
||||
#define V py_TValue
|
||||
#define NAME NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
|
||||
/* A simple binary tree for storing modules. */
|
||||
typedef struct ModuleDict {
|
||||
const char* path;
|
||||
py_TValue module;
|
||||
struct ModuleDict* left;
|
||||
struct ModuleDict* right;
|
||||
} ModuleDict;
|
||||
|
||||
void ModuleDict__ctor(ModuleDict* self, const char* path, py_TValue module);
|
||||
void ModuleDict__dtor(ModuleDict* self);
|
||||
void ModuleDict__set(ModuleDict* self, const char* key, py_TValue val);
|
||||
py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path);
|
||||
bool ModuleDict__contains(ModuleDict* self, const char* path);
|
||||
27
include/pocketpy/objects/object.h
Normal file
27
include/pocketpy/objects/object.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
typedef struct PyObject {
|
||||
py_Type type; // we have a duplicated type here for convenience
|
||||
bool gc_is_large;
|
||||
bool gc_marked;
|
||||
int slots; // number of slots in the object
|
||||
char flex[];
|
||||
} PyObject;
|
||||
|
||||
// slots >= 0, allocate N slots
|
||||
// slots == -1, allocate a dict
|
||||
|
||||
// | HEADER | <N slots> | <userdata>
|
||||
// | HEADER | <dict> | <userdata>
|
||||
|
||||
py_TValue* PyObject__slots(PyObject* self);
|
||||
NameDict* PyObject__dict(PyObject* self);
|
||||
void* PyObject__userdata(PyObject* self);
|
||||
|
||||
#define PK_OBJ_SLOTS_SIZE(slots) ((slots) >= 0 ? sizeof(py_TValue) * (slots) : sizeof(NameDict))
|
||||
|
||||
PyObject* PyObject__new(py_Type type, int slots, int size);
|
||||
void PyObject__delete(PyObject* self);
|
||||
36
include/pocketpy/objects/sourcedata.h
Normal file
36
include/pocketpy/objects/sourcedata.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
|
||||
struct SourceData {
|
||||
RefCounted rc;
|
||||
enum py_CompileMode mode;
|
||||
bool is_precompiled;
|
||||
bool is_dynamic; // for exec() and eval()
|
||||
|
||||
c11_string* filename;
|
||||
c11_string* source;
|
||||
|
||||
c11_vector /*T=const char* */ line_starts;
|
||||
c11_vector /*T=c11_string* */ _precompiled_tokens;
|
||||
};
|
||||
|
||||
typedef struct SourceData* SourceData_;
|
||||
|
||||
SourceData_ SourceData__rcnew(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic);
|
||||
bool SourceData__get_line(const struct SourceData* self,
|
||||
int lineno,
|
||||
const char** st,
|
||||
const char** ed);
|
||||
void SourceData__snapshot(const struct SourceData* self,
|
||||
c11_sbuf* ss,
|
||||
int lineno,
|
||||
const char* cursor,
|
||||
const char* name);
|
||||
@ -1,19 +1,602 @@
|
||||
#pragma once
|
||||
|
||||
#include "compiler.h"
|
||||
#include "obj.h"
|
||||
#include "repl.h"
|
||||
#include "iter.h"
|
||||
#include "base64.h"
|
||||
#include "cffi.h"
|
||||
#include "linalg.h"
|
||||
#include "easing.h"
|
||||
#include "io.h"
|
||||
#include "vm.h"
|
||||
#include "random.h"
|
||||
#include "bindings.h"
|
||||
#include "collections.h"
|
||||
#include "csv.h"
|
||||
#include "dataclasses.h"
|
||||
#include "array2d.h"
|
||||
#include "modules.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/common/export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/************* Public Types *************/
|
||||
typedef struct py_TValue py_TValue;
|
||||
typedef uint16_t py_Name;
|
||||
typedef int16_t py_Type;
|
||||
|
||||
typedef int64_t py_i64;
|
||||
typedef double py_f64;
|
||||
|
||||
typedef void (*py_Dtor)(void*);
|
||||
|
||||
#define PY_RAISE // mark a function that can raise an exception
|
||||
|
||||
typedef struct c11_sv {
|
||||
const char* data;
|
||||
int size;
|
||||
} c11_sv;
|
||||
|
||||
/// Generic reference.
|
||||
typedef py_TValue* py_Ref;
|
||||
/// An object reference which has the same lifespan as the object.
|
||||
typedef py_TValue* py_ObjectRef;
|
||||
/// A global reference which has the same lifespan as the VM.
|
||||
typedef py_TValue* py_GlobalRef;
|
||||
/// A specific location in the stack.
|
||||
typedef py_TValue* py_StackRef;
|
||||
/// An item of a container. It invalidates after the container is modified.
|
||||
typedef py_TValue* py_ItemRef;
|
||||
|
||||
/// Native function signature.
|
||||
/// @param argc number of arguments.
|
||||
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
||||
/// @return true if the function is successful.
|
||||
typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE;
|
||||
|
||||
enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE };
|
||||
|
||||
extern py_GlobalRef py_True;
|
||||
extern py_GlobalRef py_False;
|
||||
extern py_GlobalRef py_None;
|
||||
extern py_GlobalRef py_NIL;
|
||||
|
||||
/************* Global Setup *************/
|
||||
|
||||
/// Initialize pocketpy and the default VM.
|
||||
void py_initialize();
|
||||
/// Finalize pocketpy.
|
||||
void py_finalize();
|
||||
/// Get the current VM index.
|
||||
int py_currentvm();
|
||||
/// Switch to a VM.
|
||||
/// @param index index of the VM ranging from 0 to 16 (exclusive). `0` is the default VM.
|
||||
void py_switchvm(int index);
|
||||
|
||||
/// Run a source string.
|
||||
/// @param source source string.
|
||||
/// @param filename filename (for error messages).
|
||||
/// @param mode compile mode. Use `EXEC_MODE` for statements `EVAL_MODE` for expressions.
|
||||
/// @param module target module. Use NULL for the main module.
|
||||
/// @return true if the execution is successful.
|
||||
bool py_exec(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
py_Ref module) PY_RAISE;
|
||||
|
||||
/// Compile a source string into a code object.
|
||||
/// Use python's `exec()` or `eval()` to execute it.
|
||||
bool py_compile(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) PY_RAISE;
|
||||
|
||||
/// Python equivalent to `globals()`.
|
||||
void py_newglobals(py_Ref);
|
||||
/// Python equivalent to `locals()`.
|
||||
/// NOTE: Return a temporary object, which expires on the associated function return.
|
||||
void py_newlocals(py_Ref);
|
||||
|
||||
/************* Values Creation *************/
|
||||
|
||||
/// Create an `int` object.
|
||||
void py_newint(py_Ref, py_i64);
|
||||
/// Create a `float` object.
|
||||
void py_newfloat(py_Ref, py_f64);
|
||||
/// Create a `bool` object.
|
||||
void py_newbool(py_Ref, bool);
|
||||
/// Create a `str` object from a null-terminated string (utf-8).
|
||||
void py_newstr(py_Ref, const char*);
|
||||
/// Create a `str` object from a char array (utf-8).
|
||||
void py_newstrn(py_Ref, const char*, int);
|
||||
/// Create a `bytes` object with `n` UNINITIALIZED bytes.
|
||||
unsigned char* py_newbytes(py_Ref, int n);
|
||||
/// Create a `None` object.
|
||||
void py_newnone(py_Ref);
|
||||
/// Create a `NotImplemented` object.
|
||||
void py_newnotimplemented(py_Ref out);
|
||||
/// Create a `...` object.
|
||||
void py_newellipsis(py_Ref out);
|
||||
/// Create a `nil` object. `nil` is an invalid representation of an object.
|
||||
/// Don't use it unless you know what you are doing.
|
||||
void py_newnil(py_Ref);
|
||||
/// Create a `tuple` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
void py_newtuple(py_Ref, int n);
|
||||
/// Create an empty `list`.
|
||||
void py_newlist(py_Ref);
|
||||
/// Create a `list` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
void py_newlistn(py_Ref, int n);
|
||||
/// Create an empty `dict`.
|
||||
void py_newdict(py_Ref);
|
||||
/// Create an UNINITIALIZED `slice` object.
|
||||
/// You should use `py_setslot()` to set `start`, `stop`, and `step`.
|
||||
void py_newslice(py_Ref);
|
||||
/// Create a `nativefunc` object.
|
||||
void py_newnativefunc(py_Ref out, py_CFunction);
|
||||
/// Create a `function` object.
|
||||
py_Name
|
||||
py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots);
|
||||
/// Create a `boundmethod` object.
|
||||
void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func);
|
||||
|
||||
/************* Name Convertions *************/
|
||||
|
||||
/// Convert a null-terminated string to a name.
|
||||
py_Name py_name(const char*);
|
||||
/// Convert a name to a null-terminated string.
|
||||
const char* py_name2str(py_Name);
|
||||
/// Convert a name to a `c11_sv`.
|
||||
py_Name py_namev(c11_sv name);
|
||||
/// Convert a `c11_sv` to a name.
|
||||
c11_sv py_name2sv(py_Name);
|
||||
|
||||
#define py_ismagicname(name) (name <= __missing__)
|
||||
|
||||
/************* Meta Operations *************/
|
||||
|
||||
/// Create a new type.
|
||||
/// @param name name of the type.
|
||||
/// @param base base type.
|
||||
/// @param module module where the type is defined. Use `NULL` for built-in types.
|
||||
/// @param dtor destructor function. Use `NULL` if not needed.
|
||||
py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor);
|
||||
|
||||
/// Create a new object.
|
||||
/// @param out output reference.
|
||||
/// @param type type of the object.
|
||||
/// @param slots number of slots. Use -1 to create a `__dict__`.
|
||||
/// @param udsize size of your userdata.
|
||||
/// @return pointer to the userdata.
|
||||
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize);
|
||||
|
||||
/************* Type Cast *************/
|
||||
|
||||
/// Convert an `int` object in python to `int64_t`.
|
||||
py_i64 py_toint(py_Ref);
|
||||
/// Convert a `float` object in python to `double`.
|
||||
py_f64 py_tofloat(py_Ref);
|
||||
/// Cast a `int` or `float` object in python to `double`.
|
||||
/// If successful, returns true and set the value to `out`.
|
||||
/// Otherwise, return false and raise `TypeError`.
|
||||
bool py_castfloat(py_Ref, py_f64* out) PY_RAISE;
|
||||
/// Convert a `bool` object in python to `bool`.
|
||||
bool py_tobool(py_Ref);
|
||||
/// Convert a `type` object in python to `py_Type`.
|
||||
py_Type py_totype(py_Ref);
|
||||
/// Convert a `str` object in python to null-terminated string.
|
||||
const char* py_tostr(py_Ref);
|
||||
/// Convert a `str` object in python to char array.
|
||||
const char* py_tostrn(py_Ref, int* size);
|
||||
/// Convert a `str` object in python to `c11_sv`.
|
||||
c11_sv py_tosv(py_Ref);
|
||||
/// Convert a `bytes` object in python to char array.
|
||||
unsigned char* py_tobytes(py_Ref, int* size);
|
||||
/// Convert a user-defined object to its userdata.
|
||||
void* py_touserdata(py_Ref);
|
||||
|
||||
#define py_isint(self) py_istype(self, tp_int)
|
||||
#define py_isfloat(self) py_istype(self, tp_float)
|
||||
#define py_isbool(self) py_istype(self, tp_bool)
|
||||
#define py_isstr(self) py_istype(self, tp_str)
|
||||
#define py_islist(self) py_istype(self, tp_list)
|
||||
#define py_istuple(self) py_istype(self, tp_tuple)
|
||||
#define py_isdict(self) py_istype(self, tp_dict)
|
||||
|
||||
#define py_isnil(self) py_istype(self, 0)
|
||||
#define py_isnone(self) py_istype(self, tp_NoneType)
|
||||
|
||||
/// Get the type of the object.
|
||||
py_Type py_typeof(py_Ref self);
|
||||
/// Check if the object is exactly the given type.
|
||||
bool py_istype(py_Ref, py_Type);
|
||||
/// Check if the object is an instance of the given type.
|
||||
bool py_isinstance(py_Ref obj, py_Type type);
|
||||
/// Check if the derived type is a subclass of the base type.
|
||||
bool py_issubclass(py_Type derived, py_Type base);
|
||||
|
||||
/// Search the magic method from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
py_ItemRef py_tpfindmagic(py_Type, py_Name name);
|
||||
/// Search the name from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
py_ItemRef py_tpfindname(py_Type, py_Name name);
|
||||
/// Get the magic method from the given type only.
|
||||
/// The returned reference is always valid. However, its value may be `nil`.
|
||||
py_ItemRef py_tpgetmagic(py_Type type, py_Name name);
|
||||
|
||||
/// Get the type object of the given type.
|
||||
py_ItemRef py_tpobject(py_Type type);
|
||||
/// Get the type name.
|
||||
const char* py_tpname(py_Type type);
|
||||
/// Call a type to create a new instance.
|
||||
bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE;
|
||||
|
||||
/// Check if the object is an instance of the given type.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
bool py_checktype(py_Ref self, py_Type type) PY_RAISE;
|
||||
|
||||
#define py_checkint(self) py_checktype(self, tp_int)
|
||||
#define py_checkfloat(self) py_checktype(self, tp_float)
|
||||
#define py_checkbool(self) py_checktype(self, tp_bool)
|
||||
#define py_checkstr(self) py_checktype(self, tp_str)
|
||||
|
||||
/************* References *************/
|
||||
|
||||
/// Get the i-th register.
|
||||
/// All registers are located in a contiguous memory.
|
||||
py_GlobalRef py_getreg(int i);
|
||||
/// Set the i-th register.
|
||||
void py_setreg(int i, py_Ref val);
|
||||
|
||||
/// Get variable in the `__main__` module.
|
||||
py_ItemRef py_getglobal(py_Name name);
|
||||
/// Set variable in the `__main__` module.
|
||||
void py_setglobal(py_Name name, py_Ref val);
|
||||
/// Get variable in the `builtins` module.
|
||||
py_ItemRef py_getbuiltin(py_Name name);
|
||||
|
||||
/// Equivalent to `*dst = *src`.
|
||||
void py_assign(py_Ref dst, py_Ref src);
|
||||
/// Get the last return value.
|
||||
py_GlobalRef py_retval();
|
||||
|
||||
/// Get an item from the object's `__dict__`.
|
||||
/// Return `NULL` if not found.
|
||||
py_ItemRef py_getdict(py_Ref self, py_Name name);
|
||||
/// Set an item to the object's `__dict__`.
|
||||
void py_setdict(py_Ref self, py_Name name, py_Ref val);
|
||||
/// Delete an item from the object's `__dict__`.
|
||||
/// Return `true` if the deletion is successful.
|
||||
bool py_deldict(py_Ref self, py_Name name);
|
||||
/// Prepare an insertion to the object's `__dict__`.
|
||||
py_ItemRef py_emplacedict(py_Ref self, py_Name name);
|
||||
|
||||
/// Get the i-th slot of the object.
|
||||
/// The object must have slots and `i` must be in valid range.
|
||||
py_ObjectRef py_getslot(py_Ref self, int i);
|
||||
/// Set the i-th slot of the object.
|
||||
void py_setslot(py_Ref self, int i, py_Ref val);
|
||||
|
||||
/************* Inspection *************/
|
||||
|
||||
/// Get the current `function` object from the stack.
|
||||
/// Return `NULL` if not available.
|
||||
py_StackRef py_inspect_currentfunction();
|
||||
|
||||
/************* Bindings *************/
|
||||
|
||||
/// Bind a function to the object via "decl-based" style.
|
||||
/// @param obj the target object.
|
||||
/// @param sig signature of the function. e.g. `add(x, y)`.
|
||||
/// @param f function to bind.
|
||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
||||
/// Bind a method to type via "argc-based" style.
|
||||
/// @param type the target type.
|
||||
/// @param name name of the method.
|
||||
/// @param f function to bind.
|
||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
||||
/// Bind a function to the object via "argc-based" style.
|
||||
/// @param obj the target object.
|
||||
/// @param name name of the function.
|
||||
/// @param f function to bind.
|
||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
|
||||
/// Bind a property to type.
|
||||
/// @param type the target type.
|
||||
/// @param name name of the property.
|
||||
/// @param getter getter function.
|
||||
/// @param setter setter function. Use `NULL` if not needed.
|
||||
void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
|
||||
|
||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpgetmagic((type), __magic__), (f))
|
||||
|
||||
#define PY_CHECK_ARGC(n) \
|
||||
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
||||
|
||||
#define PY_CHECK_ARG_TYPE(i, type) \
|
||||
if(!py_checktype(py_arg(i), type)) return false
|
||||
|
||||
#define py_offset(p, i) ((py_Ref)((char*)p + ((i) << 4)))
|
||||
#define py_arg(i) py_offset(argv, i)
|
||||
|
||||
/************* Python Equivalents *************/
|
||||
|
||||
/// Python equivalent to `getattr(self, name)`.
|
||||
bool py_getattr(py_Ref self, py_Name name) PY_RAISE;
|
||||
/// Python equivalent to `setattr(self, name, val)`.
|
||||
bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `delattr(self, name)`.
|
||||
bool py_delattr(py_Ref self, py_Name name) PY_RAISE;
|
||||
/// Python equivalent to `self[key]`.
|
||||
bool py_getitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
/// Python equivalent to `self[key] = val`.
|
||||
bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `del self[key]`.
|
||||
bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
|
||||
/// Perform a binary operation.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged after the operation.
|
||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE;
|
||||
|
||||
#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
|
||||
#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__)
|
||||
#define py_binarymul(lhs, rhs) py_binaryop(lhs, rhs, __mul__, __rmul__)
|
||||
#define py_binarytruediv(lhs, rhs) py_binaryop(lhs, rhs, __truediv__, __rtruediv__)
|
||||
#define py_binaryfloordiv(lhs, rhs) py_binaryop(lhs, rhs, __floordiv__, __rfloordiv__)
|
||||
#define py_binarymod(lhs, rhs) py_binaryop(lhs, rhs, __mod__, __rmod__)
|
||||
#define py_binarypow(lhs, rhs) py_binaryop(lhs, rhs, __pow__, __rpow__)
|
||||
|
||||
#define py_binarylshift(lhs, rhs) py_binaryop(lhs, rhs, __lshift__, 0)
|
||||
#define py_binaryrshift(lhs, rhs) py_binaryop(lhs, rhs, __rshift__, 0)
|
||||
#define py_binaryand(lhs, rhs) py_binaryop(lhs, rhs, __and__, 0)
|
||||
#define py_binaryor(lhs, rhs) py_binaryop(lhs, rhs, __or__, 0)
|
||||
#define py_binaryxor(lhs, rhs) py_binaryop(lhs, rhs, __xor__, 0)
|
||||
#define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0)
|
||||
|
||||
/************* Stack Operations *************/
|
||||
|
||||
/// Get the i-th object from the top of the stack.
|
||||
/// `i` should be negative, e.g. (-1) means TOS.
|
||||
py_StackRef py_peek(int i);
|
||||
/// Push the object to the stack.
|
||||
void py_push(py_Ref src);
|
||||
/// Push a `nil` object to the stack.
|
||||
void py_pushnil();
|
||||
/// Push a `None` object to the stack.
|
||||
void py_pushnone();
|
||||
/// Pop an object from the stack.
|
||||
void py_pop();
|
||||
/// Shrink the stack by n.
|
||||
void py_shrink(int n);
|
||||
/// Get a temporary variable from the stack.
|
||||
py_StackRef py_pushtmp();
|
||||
/// Get the unbound method of the object.
|
||||
/// Assume the object is located at the top of the stack.
|
||||
/// If return true: `[self] -> [unbound, self]`.
|
||||
/// If return false: `[self] -> [self]` (no change).
|
||||
bool py_pushmethod(py_Name name);
|
||||
/// Call a callable object.
|
||||
/// Assume `argc + kwargc` arguments are already pushed to the stack.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack size will be reduced by `argc + kwargc`.
|
||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE;
|
||||
|
||||
/************* Modules *************/
|
||||
|
||||
/// Create a new module.
|
||||
py_GlobalRef py_newmodule(const char* path);
|
||||
/// Get a module by path.
|
||||
py_GlobalRef py_getmodule(const char* path);
|
||||
|
||||
/// Import a module.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// -1: error, 0: not found, 1: success
|
||||
int py_import(const char* path) PY_RAISE;
|
||||
|
||||
/************* Errors *************/
|
||||
|
||||
/// Raise an exception by type and message. Always return false.
|
||||
bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE;
|
||||
/// Raise an expection object. Always return false.
|
||||
bool py_raise(py_Ref) PY_RAISE;
|
||||
/// Print the current exception.
|
||||
/// The exception will be set as handled.
|
||||
void py_printexc();
|
||||
/// Format the current exception and return a null-terminated string.
|
||||
/// The result should be freed by the caller.
|
||||
/// The exception will be set as handled.
|
||||
char* py_formatexc();
|
||||
/// Check if an exception is raised.
|
||||
bool py_checkexc(bool ignore_handled);
|
||||
/// Check if the exception is an instance of the given type.
|
||||
/// If match, the exception will be set as handled.
|
||||
bool py_matchexc(py_Type type);
|
||||
/// Clear the current exception.
|
||||
/// @param p0 the unwinding point. Use `NULL` if not needed.
|
||||
void py_clearexc(py_StackRef p0);
|
||||
|
||||
#define NameError(n) py_exception(tp_NameError, "name '%n' is not defined", (n))
|
||||
#define TypeError(...) py_exception(tp_TypeError, __VA_ARGS__)
|
||||
#define RuntimeError(...) py_exception(tp_RuntimeError, __VA_ARGS__)
|
||||
#define ValueError(...) py_exception(tp_ValueError, __VA_ARGS__)
|
||||
#define IndexError(...) py_exception(tp_IndexError, __VA_ARGS__)
|
||||
#define ImportError(...) py_exception(tp_ImportError, __VA_ARGS__)
|
||||
#define ZeroDivisionError(...) py_exception(tp_ZeroDivisionError, __VA_ARGS__)
|
||||
#define AttributeError(self, n) \
|
||||
py_exception(tp_AttributeError, "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
#define UnboundLocalError(n) \
|
||||
py_exception(tp_UnboundLocalError, "local variable '%n' referenced before assignment", (n))
|
||||
|
||||
bool StopIteration();
|
||||
bool KeyError(py_Ref key) PY_RAISE;
|
||||
|
||||
/************* Operators *************/
|
||||
|
||||
/// Python equivalent to `bool(val)`.
|
||||
/// 1: true, 0: false, -1: error
|
||||
int py_bool(py_Ref val) PY_RAISE;
|
||||
|
||||
/// Compare two objects.
|
||||
/// 1: lhs == rhs, 0: lhs != rhs, -1: error
|
||||
int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
/// Compare two objects.
|
||||
/// 1: lhs < rhs, 0: lhs >= rhs, -1: error
|
||||
int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
|
||||
#define py_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__)
|
||||
#define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__)
|
||||
#define py_lt(lhs, rhs) py_binaryop(lhs, rhs, __lt__, __gt__)
|
||||
#define py_le(lhs, rhs) py_binaryop(lhs, rhs, __le__, __ge__)
|
||||
#define py_gt(lhs, rhs) py_binaryop(lhs, rhs, __gt__, __lt__)
|
||||
#define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__)
|
||||
|
||||
/// Get the hash value of the object.
|
||||
bool py_hash(py_Ref, py_i64* out) PY_RAISE;
|
||||
/// Get the iterator of the object.
|
||||
bool py_iter(py_Ref) PY_RAISE;
|
||||
/// Get the next element from the iterator.
|
||||
/// 1: success, 0: StopIteration, -1: error
|
||||
int py_next(py_Ref) PY_RAISE;
|
||||
/// Python equivalent to `lhs is rhs`.
|
||||
bool py_isidentical(py_Ref, py_Ref);
|
||||
/// Call a function.
|
||||
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged after the operation.
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE;
|
||||
|
||||
#if PK_DEBUG
|
||||
/// Call a py_CFunction in a safe way.
|
||||
/// This function does extra checks to help you debug `py_CFunction`.
|
||||
bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE;
|
||||
#else
|
||||
#define py_callcfunc(f, argc, argv) (f((argc), (argv)))
|
||||
#endif
|
||||
|
||||
/// Python equivalent to `str(val)`.
|
||||
bool py_str(py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `repr(val)`.
|
||||
bool py_repr(py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `len(val)`.
|
||||
bool py_len(py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `json.dumps(val)`.
|
||||
bool py_json(py_Ref val) PY_RAISE;
|
||||
|
||||
/************* Unchecked Functions *************/
|
||||
|
||||
py_ObjectRef py_tuple_data(py_Ref self);
|
||||
py_ObjectRef py_tuple_getitem(py_Ref self, int i);
|
||||
void py_tuple_setitem(py_Ref self, int i, py_Ref val);
|
||||
int py_tuple_len(py_Ref self);
|
||||
|
||||
py_ItemRef py_list_data(py_Ref self);
|
||||
py_ItemRef py_list_getitem(py_Ref self, int i);
|
||||
void py_list_setitem(py_Ref self, int i, py_Ref val);
|
||||
void py_list_delitem(py_Ref self, int i);
|
||||
int py_list_len(py_Ref self);
|
||||
void py_list_swap(py_Ref self, int i, int j);
|
||||
void py_list_append(py_Ref self, py_Ref val);
|
||||
void py_list_clear(py_Ref self);
|
||||
void py_list_insert(py_Ref self, int i, py_Ref val);
|
||||
|
||||
/// -1: error, 0: not found, 1: found
|
||||
int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
/// true: success, false: error
|
||||
bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
|
||||
/// -1: error, 0: not found, 1: found (and deleted)
|
||||
int py_dict_delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
/// -1: error, 0: not found, 1: found
|
||||
int py_dict_contains(py_Ref self, py_Ref key) PY_RAISE;
|
||||
/// true: success, false: error
|
||||
bool py_dict_apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx) PY_RAISE;
|
||||
/// noexcept
|
||||
int py_dict_len(py_Ref self);
|
||||
|
||||
/************* Others *************/
|
||||
|
||||
/// An utility function to read a line from stdin for REPL.
|
||||
int py_replinput(char* buf, int max_size);
|
||||
|
||||
/// Python favored string formatting. (just put here, not for users)
|
||||
/// %d: int
|
||||
/// %i: py_i64 (int64_t)
|
||||
/// %f: py_f64 (double)
|
||||
/// %s: const char*
|
||||
/// %q: c11_sv
|
||||
/// %v: c11_sv
|
||||
/// %c: char
|
||||
/// %p: void*
|
||||
/// %t: py_Type
|
||||
/// %n: py_Name
|
||||
|
||||
enum py_MagicNames {
|
||||
py_MagicNames__NULL, // 0 is reserved
|
||||
|
||||
#define MAGIC_METHOD(x) x,
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
};
|
||||
|
||||
enum py_PredefinedTypes {
|
||||
tp_object = 1,
|
||||
tp_type, // py_Type
|
||||
tp_int,
|
||||
tp_float,
|
||||
tp_bool,
|
||||
tp_str,
|
||||
tp_str_iterator,
|
||||
tp_list, // c11_vector
|
||||
tp_tuple, // N slots
|
||||
tp_array_iterator,
|
||||
tp_slice, // 3 slots (start, stop, step)
|
||||
tp_range,
|
||||
tp_range_iterator,
|
||||
tp_module,
|
||||
tp_function,
|
||||
tp_nativefunc,
|
||||
tp_boundmethod,
|
||||
tp_super, // 1 slot + py_Type
|
||||
tp_BaseException, // 2 slots (arg + inner exc)
|
||||
tp_Exception,
|
||||
tp_bytes,
|
||||
tp_namedict,
|
||||
tp_locals,
|
||||
tp_code,
|
||||
tp_dict,
|
||||
tp_dict_items, // 1 slot
|
||||
tp_property, // 2 slots (getter + setter)
|
||||
tp_star_wrapper, // 1 slot + int level
|
||||
tp_staticmethod, // 1 slot
|
||||
tp_classmethod, // 1 slot
|
||||
tp_NoneType,
|
||||
tp_NotImplementedType,
|
||||
tp_ellipsis,
|
||||
tp_generator,
|
||||
/* builtin exceptions */
|
||||
tp_StopIteration,
|
||||
tp_SyntaxError,
|
||||
tp_StackOverflowError,
|
||||
tp_IOError,
|
||||
tp_OSError,
|
||||
tp_NotImplementedError,
|
||||
tp_TypeError,
|
||||
tp_IndexError,
|
||||
tp_ValueError,
|
||||
tp_RuntimeError,
|
||||
tp_ZeroDivisionError,
|
||||
tp_NameError,
|
||||
tp_UnboundLocalError,
|
||||
tp_AttributeError,
|
||||
tp_ImportError,
|
||||
tp_AssertionError,
|
||||
tp_KeyError,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Some notes:
|
||||
|
||||
## Macros
|
||||
1. Function macros are partial functions. They can be used as normal expressions. Use the same
|
||||
naming convention as functions.
|
||||
2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use
|
||||
`UPPER_CASE` naming convention.
|
||||
3. Constant macros are used for global constants. Use `UPPER_CASE` or k-prefix naming convention.
|
||||
*/
|
||||
@ -1,106 +0,0 @@
|
||||
#ifndef POCKETPY_C_H
|
||||
#define POCKETPY_C_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
typedef struct pkpy_vm_handle pkpy_vm;
|
||||
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
||||
typedef void (*pkpy_COutputHandler)(const char*, int);
|
||||
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
|
||||
typedef int pkpy_CName;
|
||||
typedef int pkpy_CType;
|
||||
typedef const char* pkpy_CString;
|
||||
|
||||
/* Basic Functions */
|
||||
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source);
|
||||
PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module);
|
||||
PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
|
||||
|
||||
/* Stack Manipulation */
|
||||
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
||||
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||
|
||||
// int
|
||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
|
||||
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
||||
|
||||
// float
|
||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
|
||||
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
|
||||
|
||||
// bool
|
||||
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
|
||||
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
||||
|
||||
// string
|
||||
PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val);
|
||||
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
||||
|
||||
// void_p
|
||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
|
||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
||||
|
||||
// none
|
||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||
|
||||
// special push
|
||||
PK_EXPORT bool pkpy_push_null(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val);
|
||||
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name);
|
||||
|
||||
// some opt
|
||||
PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||
PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
|
||||
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
||||
|
||||
/* Error Handling */
|
||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
|
||||
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||
|
||||
/* Callables */
|
||||
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
||||
|
||||
/* Special APIs */
|
||||
PK_EXPORT void pkpy_free(void* p);
|
||||
#define pkpy_string(__s) (__s)
|
||||
PK_EXPORT pkpy_CName pkpy_name(const char* s);
|
||||
PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name);
|
||||
PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler);
|
||||
PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
|
||||
|
||||
/* REPL */
|
||||
PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
||||
PK_EXPORT void pkpy_delete_repl(void* repl);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "frame.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct _LineRecord{
|
||||
int line;
|
||||
i64 hits;
|
||||
clock_t time;
|
||||
|
||||
_LineRecord(): line(-1), hits(0), time(0) {}
|
||||
bool is_valid() const { return line != -1; }
|
||||
};
|
||||
|
||||
struct _FrameRecord{
|
||||
int callstack_size;
|
||||
Frame* frame;
|
||||
clock_t prev_time;
|
||||
_LineRecord* prev_record;
|
||||
};
|
||||
|
||||
struct LineProfiler{
|
||||
// filename -> records
|
||||
std::map<std::string_view, std::vector<_LineRecord>> records;
|
||||
stack_no_copy<_FrameRecord> frames;
|
||||
std::set<FuncDecl*> functions;
|
||||
|
||||
void begin();
|
||||
void _step(int, Frame*);
|
||||
void _step_end(int, Frame*, int);
|
||||
void end();
|
||||
Str stats();
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user