Compare commits

...

621 Commits

Author SHA1 Message Date
blueloveTH
76c251fb7f ... 2024-08-11 15:45:27 +08:00
blueloveTH
4462391daa ... 2024-08-11 15:43:25 +08:00
blueloveTH
ca459f6b65 ... 2024-08-11 15:41:07 +08:00
blueloveTH
d3a851fb46 ... 2024-08-11 14:27:26 +08:00
blueloveTH
467b3b4dba ... 2024-08-11 14:12:10 +08:00
blueloveTH
f76ba54e9f ... 2024-08-11 14:08:45 +08:00
blueloveTH
807b8a417d ... 2024-08-11 13:48:57 +08:00
blueloveTH
eb1147826e ... 2024-08-11 13:33:06 +08:00
blueloveTH
66f7bbd18c ... 2024-08-11 13:05:56 +08:00
blueloveTH
145782b789 ... 2024-08-11 12:10:56 +08:00
blueloveTH
0e7936341b ... 2024-08-11 01:14:36 +08:00
blueloveTH
2930da4e7f ... 2024-08-10 22:02:21 +08:00
blueloveTH
1b5b9fa6cb ... 2024-08-10 21:48:28 +08:00
blueloveTH
c4c7b9ef25 ... 2024-08-10 21:38:40 +08:00
blueloveTH
0f5ce54c66 ... 2024-08-10 20:29:44 +08:00
blueloveTH
88f893ddd7 ... 2024-08-10 20:21:40 +08:00
blueloveTH
76075de70c ... 2024-08-10 17:27:58 +08:00
blueloveTH
c9e688207a ... 2024-08-10 16:47:48 +08:00
blueloveTH
f27548c6df ... 2024-08-10 16:30:37 +08:00
blueloveTH
34d620c82f ... 2024-08-10 16:13:44 +08:00
blueloveTH
b51bf33572 ... 2024-08-10 16:04:50 +08:00
blueloveTH
0806b1aee1 ... 2024-08-10 13:08:31 +08:00
blueloveTH
87bf0c9e7c ... 2024-08-09 13:40:02 +08:00
blueloveTH
a96173fd6a ... 2024-08-09 13:11:56 +08:00
blueloveTH
d8f2808462 ... 2024-08-09 12:54:29 +08:00
blueloveTH
3e99f46273 fix gc issues 2024-08-09 12:28:20 +08:00
blueloveTH
3caca62f2c ... 2024-08-09 11:46:10 +08:00
blueloveTH
2eb3eabcc2 add json module 2024-08-09 11:40:20 +08:00
blueloveTH
3fbbd9fb67 ... 2024-08-09 11:04:30 +08:00
blueloveTH
651bf997fc ... 2024-08-08 20:14:59 +08:00
blueloveTH
46fb524a01 support execdyn 2024-08-08 20:04:14 +08:00
blueloveTH
41a938386a ... 2024-08-08 17:39:10 +08:00
blueloveTH
ad1482370b ... 2024-08-08 14:15:19 +08:00
blueloveTH
4829568c87 ... 2024-08-08 14:08:17 +08:00
blueloveTH
81edd22a76 add random module 2024-08-08 13:39:44 +08:00
blueloveTH
471d4ae578 ... 2024-08-08 12:24:17 +08:00
blueloveTH
22d4c07f50 ... 2024-08-08 11:12:59 +08:00
blueloveTH
cd3c28fdd8 fix generator 2024-08-08 11:09:30 +08:00
blueloveTH
f481337f98 ... 2024-08-06 19:37:44 +08:00
blueloveTH
8264f125d6 ... 2024-08-06 15:25:26 +08:00
blueloveTH
b6993532fa ... 2024-08-06 14:12:55 +08:00
blueloveTH
1c1e898950 ... 2024-08-06 14:10:46 +08:00
blueloveTH
6805b418b5 ... 2024-08-06 14:00:59 +08:00
blueloveTH
3a2e8ab6c5 ... 2024-08-06 13:56:56 +08:00
blueloveTH
c4f761d7c2 ... 2024-08-06 13:53:34 +08:00
blueloveTH
e94cfaf42e Delete run_c_binding_test.sh 2024-08-06 13:51:25 +08:00
blueloveTH
749435e516 ... 2024-08-06 13:47:41 +08:00
blueloveTH
f756bd813d ... 2024-08-06 13:31:41 +08:00
blueloveTH
bf5fe3d898 ... 2024-08-06 13:15:50 +08:00
blueloveTH
f9a1bd1d49 ... 2024-08-06 12:58:11 +08:00
blueloveTH
0bd25e7224 ... 2024-08-06 12:54:20 +08:00
blueloveTH
ceb49d832b add bytes 2024-08-06 12:46:16 +08:00
blueloveTH
6a7da5a1d5 ... 2024-08-05 23:52:09 +08:00
blueloveTH
65295f3e29 ... 2024-08-05 23:29:24 +08:00
blueloveTH
56097f6927 ... 2024-08-05 23:24:07 +08:00
blueloveTH
7ca97f03a7 ... 2024-08-05 22:36:26 +08:00
blueloveTH
ee29eadcd3 ... 2024-08-05 22:34:33 +08:00
blueloveTH
4254de48bf ... 2024-08-05 19:28:38 +08:00
blueloveTH
693026c6c4 ... 2024-08-05 19:25:57 +08:00
blueloveTH
33bea83e53 add docs for pocketpy.h 2024-08-05 19:20:40 +08:00
blueloveTH
26f53bf85d add setcomp 2024-08-05 17:48:48 +08:00
blueloveTH
f28335f1f7 add set 2024-08-05 17:48:06 +08:00
blueloveTH
9fbaca3b13 ... 2024-08-05 17:16:58 +08:00
blueloveTH
4e8920b280 ... 2024-08-05 17:11:53 +08:00
blueloveTH
0918256c90 ... 2024-08-05 17:06:21 +08:00
blueloveTH
90eb50a3a5 ... 2024-08-05 16:54:48 +08:00
blueloveTH
1735e0d3b8 ... 2024-08-05 16:53:02 +08:00
blueloveTH
50ec46fe83 ... 2024-08-05 14:20:39 +08:00
blueloveTH
0c081ba912 fix closure 2024-08-05 13:52:04 +08:00
blueloveTH
7215f48007 ... 2024-08-05 13:40:23 +08:00
blueloveTH
aa3be3b63d ... 2024-08-05 10:38:59 +08:00
blueloveTH
04804ad410 ... 2024-08-04 23:39:04 +08:00
blueloveTH
0b649f3bef ... 2024-08-04 22:45:00 +08:00
blueloveTH
a87641c04d ... 2024-08-04 22:31:33 +08:00
blueloveTH
9c173fdada ... 2024-08-04 20:38:49 +08:00
blueloveTH
348bb2b7a5 ... 2024-08-04 20:35:33 +08:00
blueloveTH
39947e8f15 ... 2024-08-04 19:18:29 +08:00
blueloveTH
56763e05f9 ... 2024-08-04 19:09:50 +08:00
blueloveTH
cd9a9f7119 ... 2024-08-04 19:04:00 +08:00
blueloveTH
ea9dabdf99 ... 2024-08-04 18:51:58 +08:00
blueloveTH
b1a8c6db8e ... 2024-08-04 16:05:47 +08:00
blueloveTH
3c87bf8630 ... 2024-08-04 15:19:49 +08:00
blueloveTH
8e1e29ddd6 add py_import 2024-08-04 14:57:59 +08:00
blueloveTH
205f6ff225 ... 2024-08-03 15:28:41 +08:00
blueloveTH
397123e3c9 support vm switch 2024-08-03 15:07:47 +08:00
blueloveTH
e04d4e790c ... 2024-08-03 14:46:24 +08:00
blueloveTH
8eff9abfbc remove py_callcfunc 2024-08-03 14:38:13 +08:00
BLUELOVETH
ab3a9b7584
Merge pull request #293 from MopedSnigelSoppa/v2.0
Fixes: warning: ISO C forbids empty initializer braces before C23
2024-07-31 18:00:23 +08:00
Fredrik Ovaska
d835ea984e Fixes: warning: ISO C forbids empty initializer braces before C23 [-Wpedantic] 2024-07-31 11:38:42 +02:00
blueloveTH
9162e84ae6 ... 2024-07-31 11:54:22 +08:00
blueloveTH
6c6e4f0512 ... 2024-07-31 11:36:21 +08:00
blueloveTH
b7950d4a11 ... 2024-07-31 00:09:45 +08:00
blueloveTH
9c028fd133 ... 2024-07-30 23:49:29 +08:00
blueloveTH
a648313fb7 ... 2024-07-30 23:44:22 +08:00
blueloveTH
66cefad078 ... 2024-07-30 18:37:18 +08:00
blueloveTH
ccca4791ae ... 2024-07-30 18:26:41 +08:00
blueloveTH
3bbcb384bd ... 2024-07-30 18:19:46 +08:00
blueloveTH
67ae21d18d ... 2024-07-30 18:12:22 +08:00
blueloveTH
db0acc854c ... 2024-07-30 12:24:47 +08:00
blueloveTH
1bbba50003 ... 2024-07-30 12:15:50 +08:00
blueloveTH
ec30ba9d02 ... 2024-07-30 12:14:07 +08:00
blueloveTH
2165e29c4f ... 2024-07-29 19:20:59 +08:00
blueloveTH
a8dfbc9147 ... 2024-07-25 20:46:41 +08:00
blueloveTH
3ea3cf7366 ... 2024-07-25 19:55:19 +08:00
blueloveTH
b6eeaa8cbc ... 2024-07-25 19:12:51 +08:00
blueloveTH
3e7ca3cddd ... 2024-07-25 16:46:27 +08:00
blueloveTH
f2363a8657 ... 2024-07-25 13:58:25 +08:00
blueloveTH
8de566f875 ... 2024-07-21 21:23:19 +08:00
blueloveTH
4f6d0999b7 ... 2024-07-21 21:17:30 +08:00
blueloveTH
2605382a79 ... 2024-07-21 21:11:18 +08:00
blueloveTH
29a989f09a allow __eq__ returns non-bool 2024-07-21 20:35:22 +08:00
blueloveTH
9d9674d171 ... 2024-07-20 22:46:23 +08:00
blueloveTH
31d095e3cc ... 2024-07-14 23:47:19 +08:00
blueloveTH
51e2433404 ... 2024-07-14 23:41:56 +08:00
blueloveTH
20cd2064d4 ... 2024-07-14 16:24:13 +08:00
blueloveTH
8f97e9419f ... 2024-07-14 13:46:56 +08:00
blueloveTH
1a4b88829c reimpl dict 2024-07-14 12:49:29 +08:00
blueloveTH
42b4c56543 ... 2024-07-14 12:49:24 +08:00
blueloveTH
c9df104634 ... 2024-07-14 12:49:19 +08:00
blueloveTH
b89414a5d7 ... 2024-07-14 12:49:15 +08:00
blueloveTH
614fc27f03 ... 2024-07-14 12:49:10 +08:00
blueloveTH
79ac343eb2 change type names 2024-07-14 12:49:04 +08:00
blueloveTH
35f03bf2e2 ... 2024-07-14 12:49:00 +08:00
blueloveTH
58d00d45b8 change test order
some fix
2024-07-14 12:49:00 +08:00
blueloveTH
f3a4473162 remove JSON_MODE and use EVAL_MODE 2024-07-14 12:49:00 +08:00
blueloveTH
554363e66f ... 2024-07-14 12:48:55 +08:00
blueloveTH
5d99323321 ... 2024-07-14 12:48:52 +08:00
blueloveTH
45de08dd39 ... 2024-07-14 12:48:48 +08:00
blueloveTH
40d6f1a19f ... 2024-07-14 12:48:45 +08:00
blueloveTH
fa5df75248 ... 2024-07-14 12:48:42 +08:00
blueloveTH
f9de245bc6 ... 2024-07-14 12:48:38 +08:00
blueloveTH
6bc625dd0c ... 2024-07-14 12:48:33 +08:00
blueloveTH
04b187923b fix cmake 2024-07-14 12:48:33 +08:00
blueloveTH
807294e0eb ... 2024-07-14 12:48:30 +08:00
blueloveTH
a2a093836f remove invalid cases 2024-07-14 12:48:30 +08:00
blueloveTH
5706e5e49d fix forloop 2024-07-14 12:48:30 +08:00
blueloveTH
f3d876c5ef remove *.cpp 2024-07-14 12:48:30 +08:00
blueloveTH
140255650d ... 2024-07-14 12:48:23 +08:00
blueloveTH
a81563768d ... 2024-07-14 12:48:18 +08:00
blueloveTH
83c54fbeac fix list 2024-07-14 12:48:18 +08:00
blueloveTH
ed02a2b172 ... 2024-07-14 12:48:14 +08:00
blueloveTH
5f98f916a9 ... 2024-07-14 12:48:11 +08:00
blueloveTH
22ae57fc9b fix list.sort 2024-07-14 12:48:11 +08:00
blueloveTH
400b8fbef4 ... 2024-07-14 12:48:05 +08:00
blueloveTH
e4c8c47c2e ... 2024-07-14 12:47:58 +08:00
blueloveTH
f34035100c ... 2024-07-14 12:47:46 +08:00
blueloveTH
b8fc853cb8 Update py_list.c 2024-07-07 03:42:53 +08:00
blueloveTH
6bcff00990 some fix 2024-07-07 03:39:36 +08:00
blueloveTH
31c95c7ba2 some update 2024-07-07 03:33:06 +08:00
blueloveTH
29aa3e5eed some fix 2024-07-07 03:27:07 +08:00
blueloveTH
1a9bad4e54 some fix 2024-07-07 02:19:37 +08:00
blueloveTH
a4718a00b2 some fix 2024-07-07 01:48:40 +08:00
blueloveTH
79012a6b08 some fix 2024-07-07 00:56:02 +08:00
blueloveTH
18fe69d579 some update 2024-07-07 00:28:41 +08:00
blueloveTH
5c959e7274 support function 2024-07-07 00:06:21 +08:00
blueloveTH
803e7f1791 some fix 2024-07-06 23:07:44 +08:00
blueloveTH
4b4351e3fa Update 01_int.py 2024-07-06 16:16:00 +08:00
blueloveTH
c9cbecc401 some fix 2024-07-06 16:15:40 +08:00
blueloveTH
403e3c9f0e some fix 2024-07-06 14:55:32 +08:00
blueloveTH
7feb3047e9 some fix 2024-07-06 14:10:03 +08:00
blueloveTH
6e1550213c some fix 2024-07-06 13:23:33 +08:00
blueloveTH
381e2d5b9a some fix 2024-07-06 01:07:31 +08:00
blueloveTH
f93aefdbe5 implement repl 2024-07-06 00:36:51 +08:00
blueloveTH
d74ca31f68 add some string bindings 2024-07-05 22:55:24 +08:00
blueloveTH
a86c134377 add bool bindings 2024-07-05 21:08:39 +08:00
blueloveTH
84004349db Update compiler.c 2024-07-05 13:38:07 +08:00
blueloveTH
8a257199a3 Update pocketpy.h 2024-07-05 12:13:53 +08:00
blueloveTH
34916d7578 Update ceval.c 2024-07-05 00:21:56 +08:00
blueloveTH
c2944b7fd8 some fix 2024-07-05 00:17:53 +08:00
blueloveTH
4569547161 Update compiler.c 2024-07-04 23:51:05 +08:00
blueloveTH
68bc6ee269 fix leaks 2024-07-04 23:47:32 +08:00
blueloveTH
3da176fbfb some rename 2024-07-04 23:20:52 +08:00
blueloveTH
3a8613b7ff improve errors 2024-07-04 22:44:37 +08:00
blueloveTH
facd1c0ce6 some fix 2024-07-04 19:55:24 +08:00
blueloveTH
8ae999ecdf some up 2024-07-03 13:34:39 +08:00
blueloveTH
6ac3fdccdb some fix 2024-07-03 12:53:54 +08:00
blueloveTH
841cc25a4e some fix 2024-07-03 01:24:29 +08:00
blueloveTH
e365124af3 some up 2024-07-03 00:48:45 +08:00
blueloveTH
1696bb6d66 some up 2024-07-02 23:34:50 +08:00
blueloveTH
8c41065258 some fix 2024-07-02 20:21:17 +08:00
blueloveTH
8fea101c8c Update strname.c 2024-07-02 20:17:06 +08:00
blueloveTH
2540205b77 some fix 2024-07-02 20:15:58 +08:00
blueloveTH
4542f23143 some rename 2024-07-02 20:01:21 +08:00
blueloveTH
c6185c3d9c improve lower_bound 2024-07-02 19:40:52 +08:00
blueloveTH
163effc00d remove unused ids 2024-07-02 19:00:38 +08:00
blueloveTH
2d9a06a3fc use enum for magic names 2024-07-02 17:52:09 +08:00
blueloveTH
cf82c409df add PredefinedTypes 2024-07-02 17:31:44 +08:00
blueloveTH
db1ae5bfa2 Update py_list.c 2024-07-02 15:06:28 +08:00
blueloveTH
8319cb2ad4 some fix 2024-07-02 15:01:04 +08:00
blueloveTH
ab0f07bbd7 some fix 2024-07-02 11:47:56 +08:00
blueloveTH
a59a68b6f5 Update str.h 2024-07-02 11:09:40 +08:00
blueloveTH
78aa295876 some fix 2024-07-02 11:06:53 +08:00
blueloveTH
8f6b539b37 some rename 2024-07-02 00:58:06 +08:00
blueloveTH
9c7d1c5fe1 a lot of rename 2024-07-02 00:55:14 +08:00
blueloveTH
bb2dfe61dc refactor string 2024-07-02 00:53:50 +08:00
blueloveTH
a9d6242a43 some fix 2024-07-01 20:06:52 +08:00
blueloveTH
7692899366 some fix 2024-07-01 19:50:04 +08:00
blueloveTH
6befe661b7 some fix 2024-07-01 18:48:57 +08:00
blueloveTH
f22191faa6 fix types 2024-07-01 14:05:43 +08:00
blueloveTH
ca7552c9f6 Update ceval.c 2024-07-01 12:42:19 +08:00
blueloveTH
fdc26c6b93 some fix 2024-07-01 12:05:12 +08:00
blueloveTH
0bafc17994 some fix 2024-07-01 11:45:14 +08:00
blueloveTH
15fd2ef8a0 some fix 2024-07-01 11:38:53 +08:00
blueloveTH
d00c058c46 Delete refcount.h 2024-07-01 02:22:21 +08:00
blueloveTH
69183e2d79 some fix 2024-07-01 02:22:03 +08:00
blueloveTH
96d0c432c7 some fix 2024-07-01 02:15:16 +08:00
blueloveTH
97cdfbedaf some fix 2024-07-01 02:03:09 +08:00
blueloveTH
ac19ece535 some fix 2024-07-01 01:55:26 +08:00
blueloveTH
c954431442 some fix 2024-07-01 01:42:08 +08:00
blueloveTH
36b3c9ff8f some fix 2024-07-01 01:28:18 +08:00
blueloveTH
5847586121 some fix 2024-07-01 00:57:14 +08:00
blueloveTH
c5ab28d75b some fix 2024-07-01 00:32:56 +08:00
blueloveTH
52b210b016 some fix 2024-07-01 00:21:03 +08:00
blueloveTH
8270d9035b add assert 2024-06-30 23:01:26 +08:00
blueloveTH
8bbb9fc5f3 some fix 2024-06-30 22:54:01 +08:00
blueloveTH
25ceed2703 backup 2024-06-30 22:44:51 +08:00
blueloveTH
7ed09f927d try list 2024-06-30 15:32:40 +08:00
blueloveTH
391d26cdc5 some fix 2024-06-30 15:26:39 +08:00
blueloveTH
68e8536c89 some fix 2024-06-30 14:34:23 +08:00
blueloveTH
a6b3163635 some fix 2024-06-30 14:27:13 +08:00
blueloveTH
4860c08e03 some test 2024-06-30 14:10:17 +08:00
blueloveTH
cde78ea481 some up 2024-06-30 02:38:38 +08:00
blueloveTH
5be3300554 fix initial demo 2024-06-29 21:14:11 +08:00
blueloveTH
f53ae5e459 some fix 2024-06-29 19:44:38 +08:00
blueloveTH
6c46705e98 some fix 2024-06-29 19:39:28 +08:00
blueloveTH
455aa576e5 some fix 2024-06-29 19:35:11 +08:00
blueloveTH
4a5f74b2d2 some move 2024-06-29 18:54:05 +08:00
blueloveTH
a55d3a5340 global replace 2024-06-29 18:34:38 +08:00
blueloveTH
773a05e25c some fix 2024-06-29 17:31:42 +08:00
blueloveTH
c4897ea0fb Update compiler.c 2024-06-29 17:21:43 +08:00
blueloveTH
0963929a30 some up 2024-06-29 17:01:09 +08:00
blueloveTH
23b523b788 some fix 2024-06-29 16:36:30 +08:00
blueloveTH
14a01c0e6d Update compiler.c 2024-06-29 14:38:52 +08:00
blueloveTH
a03a3bdbf8 some fix 2024-06-29 14:34:38 +08:00
blueloveTH
3610e87244 merge to compiler.c 2024-06-29 14:16:12 +08:00
blueloveTH
62420dade1 some fix 2024-06-29 11:21:52 +08:00
blueloveTH
c7597dfcdf some fix 2024-06-29 00:10:40 +08:00
blueloveTH
c4b52ef684 some up 2024-06-28 23:07:26 +08:00
blueloveTH
6f4617b83d Update compiler.c 2024-06-28 19:32:48 +08:00
blueloveTH
4c332b7d16 Update compiler.c 2024-06-28 19:14:36 +08:00
blueloveTH
7748d2bf03 some fix 2024-06-28 19:06:27 +08:00
blueloveTH
881e94e8b0 some fix 2024-06-28 16:17:29 +08:00
blueloveTH
72723d24f5 some fix 2024-06-28 15:58:05 +08:00
blueloveTH
1ac08cfc2b some fix 2024-06-28 15:47:11 +08:00
blueloveTH
79b9df3392 some fix 2024-06-28 15:33:23 +08:00
blueloveTH
104c266bc0 move lexer 2024-06-28 15:02:55 +08:00
blueloveTH
fa31f4c5df backup 2024-06-27 20:05:45 +08:00
blueloveTH
31fa85f22e some fix 2024-06-26 16:39:17 +08:00
blueloveTH
57563d4e40 some rename 2024-06-26 13:40:53 +08:00
blueloveTH
6956631c61 some fix 2024-06-26 13:35:28 +08:00
blueloveTH
16f1d3fcfb some fix 2024-06-26 13:24:02 +08:00
blueloveTH
b20246b172 some fix 2024-06-26 13:20:57 +08:00
blueloveTH
cff541b94b some fix 2024-06-26 13:17:29 +08:00
blueloveTH
d44781fa1e some fix 2024-06-26 13:12:30 +08:00
blueloveTH
ae002a6c17 Update pocketpy.h 2024-06-26 13:08:14 +08:00
blueloveTH
11ea812897 some fix 2024-06-26 12:52:55 +08:00
blueloveTH
73bca886b5 some fix 2024-06-26 11:28:38 +08:00
blueloveTH
13b1fbe17a cleanup 2024-06-26 03:29:25 +08:00
blueloveTH
7e35fa2d56 some fix 2024-06-26 03:23:46 +08:00
blueloveTH
fb0ec57f38 up 2024-06-26 02:50:02 +08:00
blueloveTH
2ac2ff807f up 2024-06-26 02:36:14 +08:00
blueloveTH
6f99ebed88 rename py_Type 2024-06-26 01:03:53 +08:00
blueloveTH
5bdbec273e some tidy 2024-06-26 01:02:45 +08:00
blueloveTH
0871b627ed up 2024-06-25 19:32:15 +08:00
blueloveTH
2a84911862 up 2024-06-25 14:44:18 +08:00
blueloveTH
bb67505613 up 2024-06-25 14:16:58 +08:00
blueloveTH
efd98e6a6a up 2024-06-25 04:29:53 +08:00
blueloveTH
d3d296b353 some up 2024-06-24 21:01:30 +08:00
blueloveTH
c89c7bd1ac some fix 2024-06-24 20:14:40 +08:00
blueloveTH
857b798172 some fix 2024-06-24 00:19:00 +08:00
blueloveTH
b4da713ac1 Update README.md 2024-06-24 00:08:05 +08:00
blueloveTH
19ed0fdaf5 remove *.cpp 2024-06-24 00:06:31 +08:00
blueloveTH
23d7b56c86 some move 2024-06-23 02:14:22 +08:00
blueloveTH
8b8552d54b backup 2024-06-23 01:42:29 +08:00
blueloveTH
28c3b35d39 remove CodeObject_ 2024-06-22 15:46:48 +08:00
blueloveTH
58c5bb1d35 add c11_vector__foreach 2024-06-22 15:26:20 +08:00
blueloveTH
841be061e0 some move 2024-06-22 15:07:06 +08:00
blueloveTH
783bbfb4ba some move 2024-06-22 14:49:18 +08:00
blueloveTH
aea3b4758f some move 2024-06-22 14:39:41 +08:00
blueloveTH
92fcc116af Update expr.hpp 2024-06-20 00:58:27 +08:00
blueloveTH
dbd75615d9 some rename 2024-06-20 00:27:07 +08:00
blueloveTH
1431cf8cde remove constexpr TK 2024-06-20 00:24:35 +08:00
blueloveTH
eb1806deaa some fix 2024-06-19 22:49:37 +08:00
BLUELOVETH
23ffa73f4c
Merge pull request #284 from szdytom/integrate-test-with-build-system
Integrate testing with the cmake build system
2024-06-19 16:34:09 +08:00
f4d676548f Add sanitize mode 2024-06-19 07:24:17 +00:00
blueloveTH
3e9a6256ad some fix 2024-06-19 14:25:56 +08:00
273ce0c186 add test cmake 2024-06-19 05:55:49 +00:00
blueloveTH
e1e3e208cb move gc.h 2024-06-19 13:39:37 +08:00
BLUELOVETH
f06f7e21c9
Merge pull request #277 from szdytom/fix-some-leak
Fix memory leaks
2024-06-19 11:20:52 +08:00
BLUELOVETH
2a7067cd03
Merge pull request #281 from szdytom/align-dict-hashtable
Align memory access in `Dict` hashtable
2024-06-19 11:10:27 +08:00
2c5f46f096
call s_clean before pop context 2024-06-18 23:16:38 +08:00
8aa52ba64a
align memory access in Dict hashtable 2024-06-18 21:22:31 +08:00
c4d14847e8
fix leaks 2024-06-17 21:40:50 +08:00
blueloveTH
026171e753 fix rc leak 2024-06-17 12:18:28 +08:00
blueloveTH
3a257aefb1 move error.h 2024-06-17 01:19:41 +08:00
blueloveTH
31bf7f45c4 remove source data 2024-06-17 00:42:47 +08:00
blueloveTH
5a6ede01d1 fix new_object<> 2024-06-16 22:42:45 +08:00
blueloveTH
17d0c87c96 add public.h 2024-06-16 22:22:44 +08:00
blueloveTH
ea269686b5 remove vm 2024-06-16 22:17:36 +08:00
blueloveTH
4d5e6c6b59 global setup 2024-06-16 22:04:47 +08:00
blueloveTH
9db1becebf Update base.h 2024-06-16 21:53:33 +08:00
blueloveTH
57153dc8d2 Update base.h 2024-06-16 21:53:12 +08:00
BLUELOVETH
52abebfc16
Merge pull request #276 from szdytom/add-stable-sort
add stable_sort
2024-06-16 21:47:31 +08:00
blueloveTH
a634d046be remove old smallmap 2024-06-16 21:47:18 +08:00
3728c02b87
fix for cl 2024-06-16 21:36:50 +08:00
ebdfb794ba
fix memcpy length 2024-06-16 21:26:27 +08:00
ac70331977
add stable_sort 2024-06-16 21:26:26 +08:00
blueloveTH
4b2b92c1ba fix msvc 2024-06-16 21:22:30 +08:00
blueloveTH
38040bf9fd fix msvc 2024-06-16 21:18:43 +08:00
blueloveTH
dc22d98322 fix msvc 2024-06-16 21:15:02 +08:00
blueloveTH
131c951cb3 Update vm.cpp 2024-06-16 21:12:27 +08:00
blueloveTH
78edbe7f8d fix msvc 2024-06-16 21:09:17 +08:00
blueloveTH
4e9072165b some fix 2024-06-16 21:06:15 +08:00
blueloveTH
af040fb6ef Update cJSONw.cpp 2024-06-16 20:56:39 +08:00
blueloveTH
8edb46afb4 fix everything 2024-06-16 20:54:12 +08:00
blueloveTH
e14d4e295a some fix 2024-06-16 20:16:41 +08:00
blueloveTH
dfd64e7474 some fix 2024-06-16 20:11:23 +08:00
blueloveTH
175c571fbb more move 2024-06-16 19:56:33 +08:00
blueloveTH
d21a9cffab some fix 2024-06-16 17:46:24 +08:00
blueloveTH
26815fae74 some move 2024-06-16 17:34:11 +08:00
blueloveTH
6791c0c81e fix names 2024-06-16 10:59:31 +08:00
blueloveTH
4ae8b5db3c Revert "using global symbols"
This reverts commit eb6a4d9fd043753ac637deda1c56117002c03de1.
2024-06-16 10:58:16 +08:00
blueloveTH
eb6a4d9fd0 using global symbols 2024-06-16 10:56:57 +08:00
blueloveTH
54f35ff396 some fix 2024-06-16 10:49:32 +08:00
blueloveTH
b63ae3741d some fix 2024-06-16 01:29:15 +08:00
blueloveTH
1f5e69972a Update config.h 2024-06-16 01:21:38 +08:00
blueloveTH
a5cf3aa426 leak some names in global 2024-06-16 01:21:12 +08:00
blueloveTH
e7fe38cdf7 Update smallmap.h 2024-06-16 00:50:00 +08:00
blueloveTH
72215f1a05 Update smallmap.h 2024-06-16 00:46:03 +08:00
blueloveTH
563ae74a19 some optimize 2024-06-16 00:21:53 +08:00
blueloveTH
e765e9f9bd fix msvc 2024-06-15 23:54:10 +08:00
blueloveTH
4d66290529 move namedict 2024-06-15 23:52:48 +08:00
blueloveTH
e299564b9c remove NameDict_ 2024-06-15 23:31:45 +08:00
blueloveTH
a8db1cc5e1 more move 2024-06-15 23:22:06 +08:00
blueloveTH
c4bb16e390 some fix 2024-06-15 21:41:59 +08:00
blueloveTH
225f634f33 some fix 2024-06-15 21:02:06 +08:00
blueloveTH
59afaf8263 some fix 2024-06-15 20:19:01 +08:00
blueloveTH
0e25f34135 some fix 2024-06-15 19:55:06 +08:00
blueloveTH
0ffacbbbe8 some fix 2024-06-15 19:24:58 +08:00
blueloveTH
e50761364d some fix 2024-06-15 19:17:57 +08:00
blueloveTH
2093f6f10f add smallmap 2024-06-15 19:14:15 +08:00
blueloveTH
649fb3cd98 some fix 2024-06-15 17:56:36 +08:00
blueloveTH
c98eb31a5e fix lower_bound 2024-06-15 17:20:51 +08:00
blueloveTH
baa75999b6 fix CI 2024-06-15 16:27:06 +08:00
blueloveTH
5e5548809a move memorypool 2024-06-15 16:21:32 +08:00
blueloveTH
a048bf385d update README.md 2024-06-15 14:30:29 +08:00
blueloveTH
e239c216b7 Merge branch 'v2.0-c11' into v2.0 2024-06-15 14:22:04 +08:00
blueloveTH
597abacc58 some fix 2024-06-15 14:20:21 +08:00
blueloveTH
3bd794f2fb some fix 2024-06-15 13:39:32 +08:00
blueloveTH
2d0db3dc71 add lower_bound 2024-06-15 13:34:47 +08:00
blueloveTH
eae3c69f85 backup 2024-06-15 11:56:04 +08:00
blueloveTH
e7e8b9141e Update CMakeLists.txt 2024-06-14 19:08:53 +08:00
BLUELOVETH
444434efb6
Merge pull request #271 from szdytom/make-dict-c11
Make `Dict` and `DictIter` c11
2024-06-14 14:53:10 +08:00
blueloveTH
0770c97f60 add benchmark for dict 2024-06-14 14:01:25 +08:00
blueloveTH
b236031554 add benchmark 2024-06-14 13:57:12 +08:00
blueloveTH
00a5b4d5d3 Merge branch 'v2.0-c11' into pr/271 2024-06-14 13:38:40 +08:00
33b110589d add test for dict larger than 65536 2024-06-14 13:35:32 +08:00
6649a5b987 never shrink 2024-06-14 13:13:24 +08:00
5e38f7debd remove asserts with side effect 2024-06-14 12:36:47 +08:00
6220ab029b stop using unsigned for indecies 2024-06-14 12:35:31 +08:00
681b9d7dd0 fix...and remove assert with side effect 2024-06-14 12:30:24 +08:00
7549f1b95a better dict clear 2024-06-14 12:28:55 +08:00
a8ca70ca74 more replace 2024-06-14 12:24:22 +08:00
d1763bdef1 replace reinterpret_cast with C-style cast 2024-06-14 12:21:20 +08:00
6d938d30bf make hash functions macros 2024-06-14 12:19:16 +08:00
784980af93 add marco PK_DICT_COMPACT_MODE 2024-06-14 12:09:46 +08:00
a47b52f086 optimize hashtable access 2024-06-14 12:04:39 +08:00
ed2e95b3f4 fix overflow 2024-06-14 11:10:08 +08:00
9390b0d638 use marcos to control load factor 2024-06-14 11:08:34 +08:00
21fdaeaa21 fix dict compare 2024-06-14 11:06:39 +08:00
6e780173f9 remove _version 2024-06-14 09:32:58 +08:00
3d90bd0392 change cmake back 2024-06-14 00:27:03 +01:00
d25afcaeae remove hash from entry 2024-06-14 00:27:03 +01:00
637aedabc5 Use 4 byte hash only 2024-06-14 00:27:03 +01:00
c047eafa7e optimize probe0 for less __eq__ and hash compare 2024-06-14 00:27:03 +01:00
5e6226729a skip nullptr in probe1 2024-06-14 00:27:03 +01:00
41562cf4c3 fix find and insert 2024-06-14 00:27:03 +01:00
f28b2f152e Fix 2024-06-14 00:27:03 +01:00
8458e49a30 Minimum deleted slot required to refactor 2024-06-14 00:27:03 +01:00
blueloveTH
3d72ca0cc6 remove any 2024-06-13 21:37:33 +08:00
blueloveTH
6167cb4a43 add PK_INLINE 2024-06-13 20:13:20 +08:00
b2d5708fd8 fix 2024-06-13 17:03:16 +08:00
e455e36a39 fix iteration and count 2024-06-13 16:44:41 +08:00
73c9c5a228 fix RE 2024-06-13 16:26:06 +08:00
f4e9293643 ... 2024-06-13 08:50:10 +01:00
249656039a fix uninitialize 2024-06-13 08:50:10 +01:00
d871d91adb Impl Dict and DictIter in c11 2024-06-13 08:50:10 +01:00
blueloveTH
59537c9bd0 fix msvc 2024-06-13 14:58:23 +08:00
blueloveTH
ead9d93f5b fix msvc 2024-06-13 14:48:37 +08:00
blueloveTH
9b72ae7223 fix msvc 2024-06-13 14:41:46 +08:00
blueloveTH
ca4ebf4ba7 some fix 2024-06-13 14:40:04 +08:00
blueloveTH
e1c706b08f some fix 2024-06-13 14:26:51 +08:00
blueloveTH
deec5edff9 some fix 2024-06-13 14:20:51 +08:00
blueloveTH
f0d82a19ee complete sstream 2024-06-13 13:22:29 +08:00
blueloveTH
0811f23b71 some more move 2024-06-13 13:08:19 +08:00
blueloveTH
9d6f044d33 Squashed commit of the following:
commit b584de5c3d4603a476cdd60830289104784a4942
Author: blueloveTH <blueloveth@foxmail.com>
Date:   Thu Jun 13 10:46:07 2024 +0800

    some fix

commit 1fe8a3280949d724ddab9c6b1476e1b55c5beb9d
Author: blueloveTH <blueloveth@foxmail.com>
Date:   Wed Jun 12 22:08:09 2024 +0800

    backup
2024-06-13 10:46:22 +08:00
bcf51c4535
Add the missing destructor for SourceData C++ binding (#267) 2024-06-12 11:29:38 +08:00
blueloveTH
3ae90fe9b1 some fix 2024-06-12 01:31:34 +08:00
031f189a4a
Make SourceData and SStream c11 (#266)
* Make SourceData c11

* make it compile

* add a marco

* follow up rename of c11_vetor__push

* remove isascii marco

* fix empty function name handling

* change enum back

* Remove trival accessor

* make pkpy_Str__take_buf hidden

* make it compile

* remove rcptr and use shared_ptr instead

* change enum name in C++ code back

* fix type problem

* remove strdup polyfill

* remove xmake

* ...
2024-06-11 20:28:51 +08:00
blueloveTH
2291ae5af3 fix CI 2024-06-11 13:41:38 +08:00
blueloveTH
1c9bd1836c some fix 2024-06-11 13:39:41 +08:00
blueloveTH
874d3a0b88 complete string move 2024-06-11 13:37:28 +08:00
blueloveTH
2fd92764fd fix CI 2024-06-11 12:54:54 +08:00
blueloveTH
6a70f535b3 move strip 2024-06-11 12:52:22 +08:00
blueloveTH
07e07831c3 rename subscr to slice 2024-06-11 12:46:53 +08:00
blueloveTH
f0ec979815 move escape 2024-06-11 12:25:04 +08:00
blueloveTH
3e64b3b742 some fix 2024-06-11 12:00:15 +08:00
blueloveTH
878db5a828 some rename 2024-06-11 10:51:51 +08:00
blueloveTH
0312dbc829 fix scripts 2024-06-10 22:46:21 +08:00
blueloveTH
3787a1da1d init 2024-06-10 22:38:49 +08:00
blueloveTH
907a1b7713 some fix 2024-06-09 22:40:53 +08:00
blueloveTH
ec366c15c6 some refactor 2024-06-09 21:42:06 +08:00
blueloveTH
4b687d36ff some fix 2024-06-09 21:26:54 +08:00
blueloveTH
0946c67fe0 some revert 2024-06-09 20:46:46 +08:00
blueloveTH
274cd58b49 fix more leaks 2024-06-09 20:37:49 +08:00
blueloveTH
157e64e0d8 fix a memory leak 2024-06-09 19:13:26 +08:00
blueloveTH
6c055b91b9 fix output format 2024-06-09 19:11:54 +08:00
blueloveTH
a828551eb7 add memory debug info 2024-06-09 18:44:43 +08:00
blueloveTH
bfaf1f3689 some fix about <stdexcept> 2024-06-09 17:55:42 +08:00
blueloveTH
5c486d1317 fix vargs 2024-06-09 17:33:48 +08:00
blueloveTH
8bc4427c7c Merge branch 'v2.0' of https://github.com/pocketpy/pocketpy into v2.0 2024-06-09 17:20:56 +08:00
blueloveTH
bd5cb80027 fix repl 2024-06-09 17:20:53 +08:00
blueloveTH
a53d6f1621 Update expr.hpp 2024-06-09 16:30:39 +08:00
blueloveTH
1c053af8d1 add noexcept 2024-06-09 16:18:31 +08:00
blueloveTH
bec168ab53 some fix 2024-06-09 16:13:43 +08:00
blueloveTH
8a049b06bd some fix 2024-06-09 15:27:53 +08:00
blueloveTH
c2be07b9cc some fix 2024-06-09 15:25:42 +08:00
blueloveTH
81c4853f04 use error code 2024-06-09 01:39:05 +08:00
blueloveTH
783547a481 some fix 2024-06-08 16:01:29 +08:00
blueloveTH
3dafa7573c make small_vector works with pod 2024-06-08 14:21:59 +08:00
blueloveTH
60e1f77f8d some optimize 2024-06-08 13:21:27 +08:00
blueloveTH
f359d07a02 some fix 2024-06-07 23:12:34 +08:00
blueloveTH
ca5881b6cc some fix 2024-06-07 22:56:09 +08:00
blueloveTH
17805032da some fix 2024-06-07 22:29:22 +08:00
blueloveTH
ae3a27c91d some fix about parse_uint 2024-06-07 22:26:46 +08:00
blueloveTH
4268cff072 fix py_exec 2024-06-07 21:14:33 +08:00
blueloveTH
02d3512681 some fix 2024-06-07 01:08:51 +08:00
blueloveTH
97d6f384f4 remove unused bc 2024-06-07 01:08:05 +08:00
blueloveTH
8b2b8ab83a some split 2024-06-07 00:53:18 +08:00
blueloveTH
dfd0d0532b Update vector.hpp 2024-06-06 23:50:49 +08:00
blueloveTH
5af32db45f some fix 2024-06-06 23:32:30 +08:00
blueloveTH
35cb1fba24 some fix 2024-06-06 23:30:12 +08:00
blueloveTH
b62bcb5a99 Update main.yml 2024-06-06 23:01:10 +08:00
blueloveTH
9da8b443ce Update main.yml 2024-06-06 22:57:53 +08:00
blueloveTH
c95c93499a fix all 2024-06-06 22:57:23 +08:00
ykiko
428761ea22
Some Fix. (#261)
* Some Fix.

* Fix resize.

* make some clean.

* Some fix

* Fix clear.

* Fix small vector.
2024-06-06 15:19:44 +08:00
blueloveTH
82655d46c9 some fix 2024-06-06 01:17:56 +08:00
blueloveTH
99de613655 fix vector 2024-06-06 01:04:17 +08:00
ykiko
bbe226b21f
Implement vetcor. (#260) 2024-06-05 23:47:49 +08:00
blueloveTH
52a3c74e43 some fix 2024-06-05 22:47:36 +08:00
blueloveTH
c0a855ab7a some fix 2024-06-05 21:59:19 +08:00
blueloveTH
d1e6fdc948 replace map 2024-06-05 21:32:56 +08:00
blueloveTH
be3d4ffaf9 remove stack<> 2024-06-04 23:19:07 +08:00
ykiko
1c82060daf
Format the world. (#259)
* add some clang-format offs.

* add formats.

* format the world.

* AllowShortIfStatementsOnASingleLine

* off REGION.

* Rollback vm.hpp

* Disable insert.
2024-06-04 22:55:17 +08:00
Non
0b404a51cb
Merge artifacts (#258)
* Merge artifacts

* Fix windows artifact name

* Update main.yml

---------

Co-authored-by: blueloveTH <blueloveTH@foxmail.com>
2024-06-04 22:54:10 +08:00
blueloveTH
e4671902bb fix assert 2024-06-03 22:50:44 +08:00
Non
bed679d211
Update actions/upload-artifact to v4 (#257)
* Update actions/upload-artifact to v4

> actions/upload-artifact@v3 is scheduled for deprecation on **November 30, 2024**. [Learn more.](https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/)
> Similarly, v1/v2 are scheduled for deprecation on **June 30, 2024**.
> Please update your workflow to use v4 of the artifact actions.
> This deprecation will not impact any existing versions of GitHub Enterprise Server being used by customers.

* Fix amalgamated exe path

* Fix Android artifact upload

* Fix fix Android artifact upload
2024-06-03 12:47:26 +08:00
blueloveTH
94fe68382f some fix 2024-06-03 00:03:00 +08:00
blueloveTH
bb9c5c30df some fix 2024-06-02 23:48:29 +08:00
blueloveTH
2ea64ce41f some fix 2024-06-02 23:29:20 +08:00
blueloveTH
426993552c some fix 2024-06-02 23:05:34 +08:00
blueloveTH
2b50aad4ef some fix 2024-06-02 23:00:50 +08:00
blueloveTH
663ca1ccf0 some optimize 2024-06-02 22:51:37 +08:00
blueloveTH
189c4de298 some fix 2024-06-02 22:42:40 +08:00
blueloveTH
d8e72e1466 some fix 2024-06-02 22:11:33 +08:00
blueloveTH
ed3e7856e8 format 2024-06-02 21:57:15 +08:00
blueloveTH
9b3e6bb177 some fix 2024-06-02 21:55:55 +08:00
blueloveTH
b4a836873e some fix 2024-06-02 21:33:03 +08:00
blueloveTH
62df3c9b5d some fix 2024-06-02 19:53:53 +08:00
blueloveTH
e7aababa36 some fix 2024-06-02 19:46:18 +08:00
blueloveTH
f3148ac206 some fix 2024-06-02 19:38:22 +08:00
blueloveTH
7d3bb3480a some fix 2024-06-02 18:22:36 +08:00
blueloveTH
7738142985 some fix 2024-06-02 18:17:20 +08:00
blueloveTH
097a7fe94f some fix 2024-06-02 18:14:04 +08:00
blueloveTH
2d39837f56 some fix 2024-06-02 17:23:13 +08:00
blueloveTH
fe8d102748 some fix 2024-06-02 17:20:37 +08:00
blueloveTH
10842207ea some fix 2024-06-02 17:09:42 +08:00
blueloveTH
2dfb6ed07a major refactor 2024-06-02 16:53:51 +08:00
blueloveTH
9e4277e87f some fix 2024-06-02 03:10:13 +08:00
blueloveTH
583f91399c some fix 2024-06-02 03:05:03 +08:00
blueloveTH
e33816b64b Update common.h 2024-06-02 03:02:34 +08:00
blueloveTH
8f94979e4c some fix 2024-06-02 03:02:19 +08:00
blueloveTH
060e4b8c1f some fix 2024-06-02 03:00:08 +08:00
blueloveTH
0cc3b77017 some fix 2024-06-02 02:55:35 +08:00
blueloveTH
2d739cae19 some fix 2024-06-01 22:24:59 +08:00
blueloveTH
67c86d7921 some fix 2024-06-01 22:24:07 +08:00
blueloveTH
2cbda5d920 remove some headers 2024-06-01 22:19:04 +08:00
blueloveTH
766bf5fa34 some fix 2024-06-01 21:54:39 +08:00
blueloveTH
bd364d9967 Update tuplelist.cpp 2024-06-01 21:52:36 +08:00
blueloveTH
2f96712371 refactor deque 2024-06-01 21:47:27 +08:00
blueloveTH
6aa210159a some fix 2024-06-01 19:47:42 +08:00
blueloveTH
8a5deb6ebb some fix 2024-06-01 19:44:20 +08:00
blueloveTH
75343ccb23 some fix 2024-06-01 19:39:46 +08:00
blueloveTH
589a1e7ae4 some fix 2024-06-01 19:37:41 +08:00
blueloveTH
8ef573a800 some fix 2024-06-01 19:32:19 +08:00
blueloveTH
fc84e657e3 some fix 2024-06-01 18:53:44 +08:00
blueloveTH
197d8414bb some fix 2024-06-01 18:22:50 +08:00
blueloveTH
a59592b799 use new vector impl 2024-06-01 18:18:38 +08:00
blueloveTH
ac82f6f33f some refactor 2024-06-01 14:27:26 +08:00
blueloveTH
2616c8378b some fix 2024-06-01 14:04:20 +08:00
blueloveTH
6ec4353aef some fix 2024-06-01 13:42:50 +08:00
blueloveTH
f50bbe5606 some fix 2024-06-01 13:05:00 +08:00
blueloveTH
a73685553d some fix 2024-06-01 13:02:17 +08:00
blueloveTH
eb7d63edd2 some fix 2024-06-01 12:59:14 +08:00
blueloveTH
58cd2eb78c activate CI 2024-06-01 12:54:45 +08:00
blueloveTH
1e365ca72c Squashed commit of the following:
commit 7e52f767ca130a49abb90ec922d74d2f5e9be078
Author: blueloveTH <blueloveTH@foxmail.com>
Date:   Sat Jun 1 12:49:46 2024 +0800

    some optimize

commit 3e2ad5b1fbad4367c80ea1325d1aa379282c10c4
Author: blueloveTH <blueloveTH@foxmail.com>
Date:   Sat Jun 1 12:29:53 2024 +0800

    some fix

commit bc0e530c72896a23cb6616ff4197ac36913389a4
Author: blueloveTH <blueloveTH@foxmail.com>
Date:   Sat Jun 1 00:00:47 2024 +0800

    some fix

commit f17ddcf8299c5d6803085cd3263181f44284f31b
Author: blueloveTH <blueloveTH@foxmail.com>
Date:   Fri May 31 23:56:15 2024 +0800

    some fix

commit cc63926c8bb89df2d99d8c92c2e18bd5a0180a2c
Author: blueloveTH <blueloveTH@foxmail.com>
Date:   Fri May 31 23:44:09 2024 +0800

    some fix

commit 3d3fb042651579cbdbcf3255398276ebb7b81e58
Author: blueloveTH <blueloveth@foxmail.com>
Date:   Fri May 31 17:28:13 2024 +0800

    deprecate `PK_OBJ_MARK`

commit 3df5f1cf128f157fb3a7aac2ceeeb47c55f5bb3b
Author: blueloveTH <blueloveth@foxmail.com>
Date:   Fri May 31 17:18:34 2024 +0800

    init
2024-06-01 12:50:38 +08:00
blueloveTH
17de5b3024 remove PK_UNREACHABLE() 2024-05-31 15:58:01 +08:00
ykiko
23bacf8b4d
add pybind11. (#254) 2024-05-30 23:14:31 +08:00
Janos
f9ed436d03 Fixes #248: sys.stderr.write() does not use vm->stderr_write (#249)
Signed-off-by: Janos Bonic <86970079+janosdebugs@users.noreply.github.com>
2024-05-30 00:17:59 +08:00
ykiko
5d73dfc55d
add [[noreturn]] for *Error functions to disable warning. (#247)
* add noreturn for *Error to disable warning.

* fix.
2024-05-29 21:23:39 +08:00
blueloveTH
249aac934b remove deprecated 2024-05-28 14:57:18 +08:00
blueloveTH
fec9a3e621 Update common.h 2024-05-28 13:44:51 +08:00
Vadim Grigoruk
afc0b8c58c wasm build fix (#245)
Thanks for your fix.
2024-05-27 13:33:45 +08:00
blueloveTH
bdece9e80c skip kwargc check on -1 2024-05-26 18:49:42 +08:00
blueloveTH
57b4595c11 refactor frameobject 2024-05-26 18:28:19 +08:00
blueloveTH
51170e4a47 fix a bug 2024-05-26 16:47:34 +08:00
blueloveTH
c157d85de6 Update vm.h 2024-05-26 16:20:49 +08:00
blueloveTH
c680da3154 fix bugs 2024-05-26 16:17:18 +08:00
blueloveTH
360efc0805 fix exception 2024-05-26 14:34:54 +08:00
blueloveTH
0d4bab9098 Update pocketpy.cpp 2024-05-26 13:47:10 +08:00
blueloveTH
bb94e595d1 more op__iter__ 2024-05-26 13:42:57 +08:00
blueloveTH
8f34024833 bug fix 2024-05-26 13:33:23 +08:00
blueloveTH
1de9c1f639 support stack object 2024-05-26 12:21:27 +08:00
blueloveTH
2d77622476 make array iter smaller 2024-05-26 02:14:39 +08:00
blueloveTH
4c15f278d0 add _get and _set 2024-05-26 01:53:21 +08:00
blueloveTH
70b536ea1b add more tests 2024-05-26 01:38:56 +08:00
blueloveTH
370e3e5e11 fix inplace op 2024-05-25 20:27:20 +08:00
blueloveTH
0da5644db5 Update obj.h 2024-05-25 15:06:40 +08:00
blueloveTH
d2410e12b1 add vec test v2.0 2024-05-25 14:51:15 +08:00
blueloveTH
23b3c07c51 Create vec.py 2024-05-25 14:46:42 +08:00
blueloveTH
e30a060344 Update array2d.cpp 2024-05-25 14:37:56 +08:00
blueloveTH
9a5ff3440a make range faster 2024-05-25 14:35:56 +08:00
blueloveTH
52d7133e1b cache nlocals 2024-05-25 00:31:12 +08:00
blueloveTH
1132a6ecff Update vm.cpp 2024-05-25 00:12:54 +08:00
blueloveTH
70f2a92b9f use memset 2024-05-25 00:10:00 +08:00
blueloveTH
30d968dea5 Update frame.h 2024-05-24 23:33:54 +08:00
blueloveTH
098dab4707 Revert "some fix"
This reverts commit 1b2fae94ebff1aac5bc300eb512f620d0105fc94.
2024-05-24 23:21:06 +08:00
blueloveTH
1b2fae94eb some fix 2024-05-24 23:18:36 +08:00
blueloveTH
6099e62314 change PY_NULL into nullptr 2024-05-24 23:16:29 +08:00
blueloveTH
617ff4fc77 some fix 2024-05-24 23:08:37 +08:00
blueloveTH
698566a8a7 remove co_codes 2024-05-24 22:09:08 +08:00
blueloveTH
8677538a29 Create loop_0_if.py 2024-05-24 22:06:27 +08:00
blueloveTH
ea8dd3f0e8 use relative jump 2024-05-24 22:01:48 +08:00
blueloveTH
2868a955bb some fix 2024-05-20 18:20:41 +08:00
blueloveTH
ff52c52349 merge iblock 2024-05-20 12:47:20 +08:00
blueloveTH
4c2f475671 Update retype.yml 2024-05-20 12:04:15 +08:00
blueloveTH
3edbe7cdf5 some fix 2024-05-20 11:14:09 +08:00
blueloveTH
e88744eadc some fix 2024-05-20 00:40:45 +08:00
blueloveTH
87453c80a7 some fix 2024-05-20 00:35:37 +08:00
blueloveTH
7de1d4d55a Update obj.h 2024-05-20 00:25:48 +08:00
blueloveTH
a1f7a16ddc some fix 2024-05-20 00:24:35 +08:00
blueloveTH
39ad3f2ef4 some fix 2024-05-20 00:09:48 +08:00
blueloveTH
a8b92c0ff4 some fix 2024-05-20 00:06:15 +08:00
blueloveTH
c416faf54d backup 2024-05-19 23:52:08 +08:00
blueloveTH
75d6b06509 Update common.h 2024-05-19 20:25:26 +08:00
blueloveTH
e8830e6407 Update any.h 2024-05-19 20:12:38 +08:00
blueloveTH
2081dcf979 remove vm for Dict() 2024-05-19 19:54:36 +08:00
blueloveTH
3a475a78b3 add emplace 2024-05-19 19:14:14 +08:00
blueloveTH
9a085d1767 some fix 2024-05-19 18:24:37 +08:00
blueloveTH
844813b787 some fix 2024-05-19 18:19:24 +08:00
blueloveTH
1417dc37df Update cJSONw.cpp 2024-05-19 17:54:59 +08:00
blueloveTH
4ba454f7a3 Update ceval.cpp 2024-05-19 17:50:07 +08:00
blueloveTH
f1dc9486a5 some fix 2024-05-19 17:47:40 +08:00
blueloveTH
79ae2cdc28 some fix 2024-05-19 17:42:20 +08:00
blueloveTH
2d3abde352 Update common.h 2024-05-19 17:22:13 +08:00
blueloveTH
ea3e64ec8c some fix 2024-05-19 17:06:37 +08:00
blueloveTH
4bd4ab84dc Update ceval.cpp 2024-05-19 17:02:44 +08:00
blueloveTH
16937c691c some fix 2024-05-19 16:27:29 +08:00
blueloveTH
d7c38f95b5 some fix 2024-05-19 16:21:50 +08:00
blueloveTH
8f114ad816 some fix 2024-05-19 16:10:49 +08:00
blueloveTH
9a1a7f92b7 refactor 2024-05-19 15:55:51 +08:00
blueloveTH
5e0e2c9c51 some inline 2024-05-19 01:54:08 +08:00
blueloveTH
9864fb13cc fix msvc asm bug 2024-05-19 00:23:14 +08:00
blueloveTH
f0f6a6a4fb Update ceval.cpp 2024-05-18 23:50:30 +08:00
blueloveTH
d6b3091cc9 Update ceval.cpp 2024-05-18 22:34:22 +08:00
blueloveTH
49379b177a some fix 2024-05-18 22:31:44 +08:00
blueloveTH
39dd1a8e21 some fix 2024-05-18 22:13:14 +08:00
blueloveTH
41aae44f21 Update ceval.cpp 2024-05-18 21:29:00 +08:00
blueloveTH
fd8ff0cd84 Update ceval.cpp 2024-05-18 21:14:13 +08:00
blueloveTH
d10ab9f70d Update ceval.cpp 2024-05-18 21:08:54 +08:00
blueloveTH
236902c629 some fix 2024-05-18 20:02:12 +08:00
blueloveTH
fb2c168a20 some fix 2024-05-18 19:23:41 +08:00
blueloveTH
0c9e49a30d some fix 2024-05-18 17:51:09 +08:00
blueloveTH
db725f8b5f Update obj.h 2024-05-18 17:41:37 +08:00
blueloveTH
6863f63a8f Update main.cpp 2024-05-18 17:33:09 +08:00
blueloveTH
4909a7f61b some fix 2024-05-18 17:30:20 +08:00
blueloveTH
e4cbb88e1d Update run_profile.sh 2024-05-18 15:35:15 +08:00
blueloveTH
9affb3a214 Update cmake_build.py 2024-05-18 14:41:33 +08:00
blueloveTH
689db5b032 some remove 2024-05-14 00:12:33 +08:00
blueloveTH
7e06cc2e96 fix a bug 2024-05-14 00:06:15 +08:00
blueloveTH
f44ba19be3 fix tests 2024-05-13 23:47:23 +08:00
blueloveTH
5b3231951f fix tests 2024-05-13 23:44:24 +08:00
blueloveTH
d3fd70a98d some fix 2024-05-13 23:34:05 +08:00
blueloveTH
979364f274 debug 2024-05-13 22:46:26 +08:00
blueloveTH
b8a2ad9652 fix an unittest 2024-05-13 21:45:09 +08:00
blueloveTH
265ab42eb0 some fix 2024-05-13 21:28:31 +08:00
blueloveTH
d33755538a some fix 2024-05-13 20:27:47 +08:00
blueloveTH
87b3697e1c Update linalg.cpp 2024-05-13 20:18:58 +08:00
blueloveTH
f03f4ebefd some fix 2024-05-13 19:46:35 +08:00
blueloveTH
393952d800 some fix 2024-05-13 18:03:56 +08:00
blueloveTH
1714195da4 some fix 2024-05-13 17:50:51 +08:00
blueloveTH
0a31183e60 some fix 2024-05-13 17:10:24 +08:00
blueloveTH
6485bf3576 Update 80_linalg.py 2024-05-13 16:58:34 +08:00
blueloveTH
e624034250 Update 80_linalg.py 2024-05-13 16:56:11 +08:00
blueloveTH
4e8b0ea9d5 some fix 2024-05-13 16:53:03 +08:00
blueloveTH
7bfe8d4bbf Update common.h 2024-05-13 16:50:56 +08:00
blueloveTH
8203ef465e enable CI 2024-05-13 16:47:09 +08:00
blueloveTH
acd81b6fae some fix 2024-05-13 16:43:40 +08:00
blueloveTH
e19c2ccf96 some fix 2024-05-13 16:20:51 +08:00
blueloveTH
a09def4ec3 some fix 2024-05-13 16:16:17 +08:00
blueloveTH
f708fc4f98 some fix 2024-05-13 15:16:01 +08:00
blueloveTH
7e2c4ea05f Update config.h 2024-05-13 15:01:07 +08:00
blueloveTH
0aea2f277e Update 99_builtin_func.py 2024-05-13 15:00:23 +08:00
blueloveTH
de912bf92f Update config.h 2024-05-13 14:59:04 +08:00
blueloveTH
a91400429b some fix 2024-05-13 14:46:28 +08:00
blueloveTH
049a5fadee some fix 2024-05-13 02:28:37 +08:00
blueloveTH
bf481b84dc some fix 2024-05-13 02:20:11 +08:00
blueloveTH
47463290a6 some fix 2024-05-13 02:04:19 +08:00
blueloveTH
cef275f900 some fix 2024-05-13 01:59:38 +08:00
blueloveTH
529c23043c a lot of fix 2024-05-13 01:24:17 +08:00
blueloveTH
f5a4c37968 init 2024-05-12 23:43:06 +08:00
298 changed files with 20887 additions and 25592 deletions

83
.clang-format Normal file
View 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"]

View File

@ -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

Binary file not shown.

View File

@ -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
View File

@ -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

View File

@ -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
)

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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;
}
```

View File

@ -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

Binary file not shown.

20
benchmarks/dict_0.py Normal file
View 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
View 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

View File

@ -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
View File

@ -0,0 +1,3 @@
for i in range(10000000):
if i > 0:
pass

23
benchmarks/vec.py Normal file
View 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)

View File

@ -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."

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,5 @@
set -e
rm -rf build
mkdir build
cd build

View File

@ -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

View File

@ -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
)

View File

@ -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;
}

View File

@ -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')]

View File

@ -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")

View File

@ -1,11 +1,5 @@
-xc++
-Wall
-W*
-std=c++17
-stdlib=libc++
-xc
-std=c11
-Iinclude/
-I3rd/cjson/include/
-I3rd/lua_bridge/include/

View File

@ -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`.

View File

@ -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]
```

View File

@ -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);
}
}
}

View File

@ -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));
```

View File

@ -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
```

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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)",

View File

@ -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:

View File

@ -1,3 +1,3 @@
#pragma once
#include "pocketpy/pocketpy.h"
#include "pocketpy/pocketpy.h"

3
include/pocketpy.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
#include "pocketpy/pocketpy.h"

View File

@ -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

View File

@ -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

View File

@ -1,9 +0,0 @@
#pragma once
#include "bindings.h"
namespace pkpy {
void add_module_array2d(VM* vm);
} // namespace pkpy

View File

@ -1,9 +0,0 @@
#pragma once
#include "bindings.h"
namespace pkpy {
void add_module_base64(VM* vm);
} // namespace pkpy

View File

@ -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

View File

@ -1,4 +0,0 @@
#pragma once
#include "vm.h"
// dummy header for ceval.cpp

View File

@ -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

View File

@ -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

View File

@ -1,8 +0,0 @@
#pragma once
#include "bindings.h"
namespace pkpy
{
void add_module_collections(VM *vm);
} // namespace pkpy

View File

@ -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

View 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[];

View 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);

View 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

View File

@ -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

View 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);

View 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

View 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, ...);

View 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);

View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
#include "pocketpy/common/str.h"
void py_Name__initialize();
void py_Name__finalize();

View 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)

View 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++)

View File

@ -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

View 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);

View 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}

View File

@ -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

View File

@ -1,9 +0,0 @@
#pragma once
#include "bindings.h"
namespace pkpy {
void add_module_csv(VM* vm);
} // namespace pkpy

View File

@ -1,9 +0,0 @@
#pragma once
#include "bindings.h"
namespace pkpy{
void add_module_dataclasses(VM* vm);
} // namespace pkpy

View File

@ -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

View File

@ -1,9 +0,0 @@
#pragma once
#include "bindings.h"
namespace pkpy{
void add_module_easing(VM* vm);
} // namespace pkpy

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
#pragma once
#include "pocketpy/interpreter/vm.hpp"
// dummy header for ceval.cpp

View 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);

View 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);

View 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);

View 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();

View 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);

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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");

View 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);

View 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);

View 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);

View 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);

View 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);

View File

@ -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.
*/

View File

@ -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

View File

@ -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