mirror of
https://github.com/micropython/micropython.git
synced 2025-12-25 06:10:13 +01:00
Compare commits
710 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110ba35980 | ||
|
|
1ac6faa732 | ||
|
|
516b09efc3 | ||
|
|
b796e3d848 | ||
|
|
16ee30c6fa | ||
|
|
fe3d16e8c2 | ||
|
|
a97e091d4e | ||
|
|
a75b02ea9b | ||
|
|
ad4c014d46 | ||
|
|
b7f7c655ed | ||
|
|
f3c3010ffc | ||
|
|
b427d6ae86 | ||
|
|
f05b87bd63 | ||
|
|
3b72da674e | ||
|
|
6cf8dd4f51 | ||
|
|
e00fb08f99 | ||
|
|
f4ce26de5c | ||
|
|
db63660c19 | ||
|
|
3bb7efc943 | ||
|
|
cd021bfe56 | ||
|
|
779794a680 | ||
|
|
fa1a9bc9fd | ||
|
|
994bb4a839 | ||
|
|
34e43c7ee9 | ||
|
|
3475b04101 | ||
|
|
29c92a407c | ||
|
|
2bf044442e | ||
|
|
8c0add4eee | ||
|
|
e5cbb70328 | ||
|
|
9480138f0c | ||
|
|
7310fd469a | ||
|
|
1d8a06406a | ||
|
|
2c4e67e32d | ||
|
|
3d945559d4 | ||
|
|
c668d51b08 | ||
|
|
8ba832456e | ||
|
|
6678595e7e | ||
|
|
3c658a4e75 | ||
|
|
25fc41dd31 | ||
|
|
4f9ebade60 | ||
|
|
72b115cbaa | ||
|
|
26a0d4f4f1 | ||
|
|
69b7dae362 | ||
|
|
d5e7f6e37e | ||
|
|
13ec400f28 | ||
|
|
7fe2191c9b | ||
|
|
86de21b810 | ||
|
|
339bdccc58 | ||
|
|
3688414d9d | ||
|
|
8f81b5cb4b | ||
|
|
b63be37be1 | ||
|
|
b0accc8571 | ||
|
|
d779b9642f | ||
|
|
244476e3e6 | ||
|
|
c84aa41990 | ||
|
|
f0c3a7e781 | ||
|
|
6009309c33 | ||
|
|
e6c0dff967 | ||
|
|
a5190a7dac | ||
|
|
2ac4af6946 | ||
|
|
6be0b0a8ec | ||
|
|
bf133f7737 | ||
|
|
2c781eabbd | ||
|
|
9b7a8ee8f1 | ||
|
|
8cce8b7c4c | ||
|
|
9d02780eaf | ||
|
|
1ddd844815 | ||
|
|
5073d3da07 | ||
|
|
8882c20b8f | ||
|
|
510296f25a | ||
|
|
75ec22bf11 | ||
|
|
105e32f1a5 | ||
|
|
f20375eedd | ||
|
|
bb91f1195a | ||
|
|
4c03b3a899 | ||
|
|
69c5fe1df6 | ||
|
|
2eb1f604ee | ||
|
|
7703d71938 | ||
|
|
9749b2fb0d | ||
|
|
2eeeafcba5 | ||
|
|
6e6bcccdc1 | ||
|
|
101d87da6a | ||
|
|
0c5498540b | ||
|
|
ecca53bd34 | ||
|
|
2831a8f800 | ||
|
|
4ef26c14b1 | ||
|
|
30dd23aa7f | ||
|
|
0c64c634ca | ||
|
|
c4ee39dd63 | ||
|
|
5f930337bc | ||
|
|
7133d91773 | ||
|
|
5f47ebbf82 | ||
|
|
2605df3346 | ||
|
|
04019e365f | ||
|
|
590b2abdfc | ||
|
|
ea439e59d9 | ||
|
|
ef7a066c9c | ||
|
|
4162271181 | ||
|
|
b92e7533d3 | ||
|
|
284efa89ae | ||
|
|
4b67463be1 | ||
|
|
5b7c0c437b | ||
|
|
196773505a | ||
|
|
a1d3ee376c | ||
|
|
6f418fc1b0 | ||
|
|
5d9b816449 | ||
|
|
3ef911345c | ||
|
|
8a11d693cf | ||
|
|
2fe2a05f9f | ||
|
|
95ea4f0c95 | ||
|
|
7cc20e7e99 | ||
|
|
56da07dcfa | ||
|
|
dd07023cb7 | ||
|
|
6c70511835 | ||
|
|
0538a203e5 | ||
|
|
2e3e8b2f69 | ||
|
|
ccacdf44b6 | ||
|
|
8dbbbbc793 | ||
|
|
aa6228eaf5 | ||
|
|
ecb5792f88 | ||
|
|
8362bffb2e | ||
|
|
ce23f67d9e | ||
|
|
e40c72210f | ||
|
|
2e41646eb7 | ||
|
|
87bbb388db | ||
|
|
71bed1a9a7 | ||
|
|
8464be15ed | ||
|
|
f8f963a14a | ||
|
|
65dd7bc13d | ||
|
|
5aac6aa445 | ||
|
|
4747becc64 | ||
|
|
8cc2018d47 | ||
|
|
c9aa58e638 | ||
|
|
bb4c6f35c6 | ||
|
|
fa1ecda3fd | ||
|
|
3c4db9f91c | ||
|
|
5f27a7e811 | ||
|
|
94fbe9711a | ||
|
|
07133415d2 | ||
|
|
d0f5e61ab5 | ||
|
|
645582fe14 | ||
|
|
adf0f2ae1a | ||
|
|
5b7fd20fea | ||
|
|
05c255f039 | ||
|
|
ffe911d228 | ||
|
|
1bbdd4ed2a | ||
|
|
4ecb700fe3 | ||
|
|
e1b1abc1e8 | ||
|
|
de993f4573 | ||
|
|
7cfae9693b | ||
|
|
3e0bce3587 | ||
|
|
7a03b5f56a | ||
|
|
86f0b31bcf | ||
|
|
1d8816c36b | ||
|
|
a2e7a1315d | ||
|
|
512465bc66 | ||
|
|
721d6240c9 | ||
|
|
4038f513ea | ||
|
|
951ed9d02f | ||
|
|
1163cb9cb5 | ||
|
|
cb66f41ebc | ||
|
|
04c9fec7d1 | ||
|
|
2c0701101b | ||
|
|
1694bc733d | ||
|
|
02bc882c3d | ||
|
|
0f4ee2e44a | ||
|
|
5467186b0e | ||
|
|
e3737b858a | ||
|
|
a4022c92f0 | ||
|
|
a50494ab68 | ||
|
|
db56ad2915 | ||
|
|
73ab8cc21d | ||
|
|
ef204733d6 | ||
|
|
0429d35f37 | ||
|
|
04f5ae1d1c | ||
|
|
4d9dd26818 | ||
|
|
dce8876dbe | ||
|
|
ac736f15c9 | ||
|
|
122c9db3db | ||
|
|
a1760a56ff | ||
|
|
b82f34edde | ||
|
|
2cf381081a | ||
|
|
564e46452d | ||
|
|
58c9586c34 | ||
|
|
847a6b30b1 | ||
|
|
e687fdbcbc | ||
|
|
2097c8b1e1 | ||
|
|
8215847b4d | ||
|
|
42b6419056 | ||
|
|
594699bc88 | ||
|
|
90ba80dc36 | ||
|
|
5fa5ca40e6 | ||
|
|
539681fffd | ||
|
|
0182385ab0 | ||
|
|
4e0eeebdc2 | ||
|
|
381618269a | ||
|
|
54eb4e723e | ||
|
|
40f3c02682 | ||
|
|
065aba5875 | ||
|
|
e4e55047b3 | ||
|
|
5e6419cb11 | ||
|
|
e70b5dbe58 | ||
|
|
92a47b4dae | ||
|
|
9cd96cf25d | ||
|
|
f83debc716 | ||
|
|
7a37f647a5 | ||
|
|
5fc580475f | ||
|
|
f0b29729aa | ||
|
|
f065344d3b | ||
|
|
aa47f3968b | ||
|
|
2fe841d2fa | ||
|
|
caa7334141 | ||
|
|
e95b6b5e07 | ||
|
|
0d81c133b3 | ||
|
|
5d44e6a92c | ||
|
|
4039a26679 | ||
|
|
b601d9574a | ||
|
|
5813efd634 | ||
|
|
bb35f425f9 | ||
|
|
c10a4405cd | ||
|
|
a23475979b | ||
|
|
ec6fa8732b | ||
|
|
8139494e54 | ||
|
|
9e215fa4c2 | ||
|
|
a62da515af | ||
|
|
5478ed18ea | ||
|
|
b1b840554d | ||
|
|
635b60e299 | ||
|
|
8546ce1e28 | ||
|
|
41736f8201 | ||
|
|
e04a44e2f6 | ||
|
|
b3a50f0f3e | ||
|
|
8993fb6cf0 | ||
|
|
7e4ec3bf4f | ||
|
|
81df1e6c98 | ||
|
|
cb78f862cb | ||
|
|
0a1ea40273 | ||
|
|
8a96ebea75 | ||
|
|
64c58403ef | ||
|
|
a75e382a9b | ||
|
|
3c8ce38d20 | ||
|
|
3659af97c5 | ||
|
|
ed07d035d5 | ||
|
|
f5f6c3b792 | ||
|
|
ce81312d8a | ||
|
|
63143c94ce | ||
|
|
ea2c936c7e | ||
|
|
26fda6dc8e | ||
|
|
00c904b47a | ||
|
|
1044c3dfe6 | ||
|
|
b1949e4c09 | ||
|
|
5048df0b7c | ||
|
|
46d31e9ca9 | ||
|
|
ded0fc77f7 | ||
|
|
17994d1bd3 | ||
|
|
79b7fe2ee5 | ||
|
|
cdc020da4b | ||
|
|
e7f2b4c875 | ||
|
|
86d3898e70 | ||
|
|
d215ee1dc1 | ||
|
|
9731912ccb | ||
|
|
165eb69b86 | ||
|
|
42a52516fe | ||
|
|
2ba2299d28 | ||
|
|
1e3781bc35 | ||
|
|
9a1a4beb56 | ||
|
|
64b468d873 | ||
|
|
83865347db | ||
|
|
c88987c1af | ||
|
|
12bc13eeb8 | ||
|
|
16ac4962ae | ||
|
|
7a8ab5a730 | ||
|
|
23668698cb | ||
|
|
91b576d147 | ||
|
|
f170735b73 | ||
|
|
f3de62e6c2 | ||
|
|
8e01291c18 | ||
|
|
7a2f166949 | ||
|
|
39b6e27944 | ||
|
|
5aa740c3e2 | ||
|
|
e973acde81 | ||
|
|
939c2e7f44 | ||
|
|
3c9b24bebe | ||
|
|
141df2d350 | ||
|
|
780e54cdc3 | ||
|
|
cd590cbfaa | ||
|
|
ff5932a8d8 | ||
|
|
949a49c9da | ||
|
|
69d0a1c540 | ||
|
|
de5ce6d461 | ||
|
|
8abcf666cb | ||
|
|
a96cc824bd | ||
|
|
59c675a64c | ||
|
|
89b38d96c9 | ||
|
|
5c8db48541 | ||
|
|
4c4b9d15ab | ||
|
|
0fc7efb663 | ||
|
|
17a49431d4 | ||
|
|
7cd46a12ae | ||
|
|
7e56e55252 | ||
|
|
eecf3e90c6 | ||
|
|
2099b6897f | ||
|
|
f605172d2b | ||
|
|
3b6f7b95eb | ||
|
|
7efbd325bb | ||
|
|
09e3f8f0d1 | ||
|
|
b6af4c8104 | ||
|
|
74c710187c | ||
|
|
59ced651b5 | ||
|
|
17db096505 | ||
|
|
e53d2197e4 | ||
|
|
f6932d6506 | ||
|
|
bf3366a48b | ||
|
|
fe81eea967 | ||
|
|
b0851e5949 | ||
|
|
c3cabf4e33 | ||
|
|
afc67c6dc5 | ||
|
|
9acb5e4cf0 | ||
|
|
def10cecd1 | ||
|
|
720f55cc4b | ||
|
|
bcb3ab451b | ||
|
|
535b88133c | ||
|
|
bbcea3f62b | ||
|
|
4f1b7fec9f | ||
|
|
2547928148 | ||
|
|
c0711cbefa | ||
|
|
e79c6696c5 | ||
|
|
34ab8dd6dd | ||
|
|
0294661da5 | ||
|
|
812025bd83 | ||
|
|
5f6f47a688 | ||
|
|
00db5c81e1 | ||
|
|
34e7b67d3c | ||
|
|
e3cfc0d33d | ||
|
|
7ddbd1bee7 | ||
|
|
b0bb458810 | ||
|
|
2ec38a17d4 | ||
|
|
e9036c295c | ||
|
|
c037694957 | ||
|
|
63b2237323 | ||
|
|
e22cddbe2a | ||
|
|
f33385f56d | ||
|
|
8340c48389 | ||
|
|
fbdf2f1d63 | ||
|
|
8a0801ad24 | ||
|
|
73c98d8709 | ||
|
|
0c0f446840 | ||
|
|
f4bf065dac | ||
|
|
5f4a667ea4 | ||
|
|
f77d0c5bb3 | ||
|
|
49df795d1d | ||
|
|
820896746c | ||
|
|
b7572ad11b | ||
|
|
58cbb4d661 | ||
|
|
62f7ba7a81 | ||
|
|
1f44e118f0 | ||
|
|
195de3247b | ||
|
|
639863d36e | ||
|
|
57b4dfa9c9 | ||
|
|
26a95ae1e7 | ||
|
|
4297fed1c3 | ||
|
|
70c289a7a6 | ||
|
|
4480cb3711 | ||
|
|
df896eceef | ||
|
|
9e951498b2 | ||
|
|
049a7a8153 | ||
|
|
c06427c019 | ||
|
|
b4efac14cd | ||
|
|
d31a093f9c | ||
|
|
5473f743f3 | ||
|
|
f0778a7ccb | ||
|
|
b9b9354e6c | ||
|
|
7e4a2b0edc | ||
|
|
aabd83ea20 | ||
|
|
82ed3d62f6 | ||
|
|
a9b5248e18 | ||
|
|
dc931934b3 | ||
|
|
585a3394df | ||
|
|
0c90eb1658 | ||
|
|
8ffc02495f | ||
|
|
c61be8e1e1 | ||
|
|
180751fbf3 | ||
|
|
de09caaa37 | ||
|
|
d72bc2713a | ||
|
|
b56a53dfd6 | ||
|
|
8c75bd26e2 | ||
|
|
b69f9fa31f | ||
|
|
380f147d2e | ||
|
|
a3ef8087e8 | ||
|
|
047db2299c | ||
|
|
88b11b50e5 | ||
|
|
755a55f507 | ||
|
|
d4c2bddd0c | ||
|
|
f675ff3957 | ||
|
|
11de8399fe | ||
|
|
daf973ae00 | ||
|
|
c074cd38c3 | ||
|
|
75ce9256b2 | ||
|
|
7a6e09635a | ||
|
|
df3ab07994 | ||
|
|
1e82ef3ae8 | ||
|
|
76c8a4c91b | ||
|
|
9ab8ab2117 | ||
|
|
30583f58d5 | ||
|
|
95fd3528c1 | ||
|
|
9b967dd3cd | ||
|
|
4867413e69 | ||
|
|
82560fce75 | ||
|
|
29bf7393c1 | ||
|
|
0a1dbfe02f | ||
|
|
c3c353d7f1 | ||
|
|
3d5ffa8318 | ||
|
|
b294a7e3c9 | ||
|
|
3f52262465 | ||
|
|
65ec33200a | ||
|
|
bcb6ca4d5e | ||
|
|
07995e9479 | ||
|
|
411732e93b | ||
|
|
b8f117dd32 | ||
|
|
d3439d0c60 | ||
|
|
509c7a7854 | ||
|
|
4e0573e5cf | ||
|
|
f753971e5d | ||
|
|
a4ac5b9f05 | ||
|
|
dd0dee3afc | ||
|
|
2abfeebf4a | ||
|
|
65a97e8d9c | ||
|
|
586f02a015 | ||
|
|
a5892a13b4 | ||
|
|
a7d963d171 | ||
|
|
d7da92a8f0 | ||
|
|
8db7804496 | ||
|
|
569aa90137 | ||
|
|
8bf8404c15 | ||
|
|
b325d25e46 | ||
|
|
62798831be | ||
|
|
b55a59de4c | ||
|
|
517f292c8d | ||
|
|
15a5738e1d | ||
|
|
fcc9cf63f1 | ||
|
|
f1dbd78b30 | ||
|
|
9500e98433 | ||
|
|
f917f06384 | ||
|
|
c49ddb9315 | ||
|
|
3ebd4d0cae | ||
|
|
fb510b3bf9 | ||
|
|
c60a261ef0 | ||
|
|
c7969857f4 | ||
|
|
1b87d1098a | ||
|
|
f94cc975a2 | ||
|
|
fa82aa81c0 | ||
|
|
6c13d7965e | ||
|
|
4d659f566f | ||
|
|
6e18835b94 | ||
|
|
a053e37b2c | ||
|
|
e7412ab37b | ||
|
|
5b5562c1d1 | ||
|
|
049a01d148 | ||
|
|
b4ebad3310 | ||
|
|
b16523aa95 | ||
|
|
ff8da0b835 | ||
|
|
ae9c82d5f3 | ||
|
|
f69b9d379c | ||
|
|
69a8b23651 | ||
|
|
a3f4b83018 | ||
|
|
b5fb9b22e2 | ||
|
|
1f07b7e3c3 | ||
|
|
3dfa76cb85 | ||
|
|
914bcf16d8 | ||
|
|
b30a777ace | ||
|
|
347b3a3d1f | ||
|
|
50b08c920a | ||
|
|
ccd0e0afcd | ||
|
|
25c84643b6 | ||
|
|
8827682b35 | ||
|
|
bcdffe53c6 | ||
|
|
059f95b2cb | ||
|
|
97953f6ce7 | ||
|
|
f55cf10101 | ||
|
|
48d641e41a | ||
|
|
d1e355ea8e | ||
|
|
813ed3bda6 | ||
|
|
503d611033 | ||
|
|
1d567592b1 | ||
|
|
8ac3b578e5 | ||
|
|
168a9ce863 | ||
|
|
ae13758dd7 | ||
|
|
4de2fe10b4 | ||
|
|
34c24a0fc2 | ||
|
|
6e76f7bc90 | ||
|
|
0405b2210d | ||
|
|
d07bf029b7 | ||
|
|
d8675541a9 | ||
|
|
f600a6a085 | ||
|
|
2617eebf2f | ||
|
|
f88fc7bd23 | ||
|
|
5042bce8fb | ||
|
|
5fd5af98d0 | ||
|
|
de4b9329f9 | ||
|
|
3aaabd11a0 | ||
|
|
ff4b6daa4f | ||
|
|
2705f4c782 | ||
|
|
69d081a7cf | ||
|
|
afaaf535e6 | ||
|
|
7a4ddd2428 | ||
|
|
ee3fd46f13 | ||
|
|
d0ceb04b90 | ||
|
|
d098c6bf85 | ||
|
|
561789d718 | ||
|
|
806ea1f6ca | ||
|
|
0c937fa25a | ||
|
|
efaef6eea3 | ||
|
|
90886807a1 | ||
|
|
58ebde4664 | ||
|
|
a8408a8abe | ||
|
|
6a410789b8 | ||
|
|
aa7cf6f72f | ||
|
|
63436ce22e | ||
|
|
0fd01683c6 | ||
|
|
6ac5dced24 | ||
|
|
6d197740cf | ||
|
|
008343f640 | ||
|
|
053765414c | ||
|
|
32acd4b9f1 | ||
|
|
44a949d58c | ||
|
|
9e29666bf9 | ||
|
|
52386cafa0 | ||
|
|
66ab571cca | ||
|
|
13684fd60b | ||
|
|
eee31288dd | ||
|
|
2de4d59171 | ||
|
|
f905ebb173 | ||
|
|
404f7cf902 | ||
|
|
9bf4f7e3d3 | ||
|
|
7ae8e4b679 | ||
|
|
5cdff5fa61 | ||
|
|
7ba0fedf13 | ||
|
|
bf27140193 | ||
|
|
ab7bf28489 | ||
|
|
c18ef2a9dd | ||
|
|
70328e419a | ||
|
|
ad3baec12f | ||
|
|
767e45c290 | ||
|
|
a47b64ae2d | ||
|
|
0c124c3123 | ||
|
|
2a27365854 | ||
|
|
51fab28e94 | ||
|
|
f6e430f77f | ||
|
|
aeeb448eb6 | ||
|
|
da9f0924ef | ||
|
|
7074f25768 | ||
|
|
561e425903 | ||
|
|
cc97446ca5 | ||
|
|
915197a8f9 | ||
|
|
97f9a2813e | ||
|
|
96f137b24a | ||
|
|
f42dbb98d1 | ||
|
|
df94b717b4 | ||
|
|
da1fffaa09 | ||
|
|
ceac71f1f5 | ||
|
|
1b901c320b | ||
|
|
6caae0bcb1 | ||
|
|
147c80bf7c | ||
|
|
5ebd5f0f19 | ||
|
|
bfb8819c0c | ||
|
|
5e5d69b35e | ||
|
|
7e7940c39d | ||
|
|
c48d6f7add | ||
|
|
0f570cfccf | ||
|
|
ff30666c69 | ||
|
|
a0863158f5 | ||
|
|
96b62855b5 | ||
|
|
ee7a880d6e | ||
|
|
5f9ebd36cd | ||
|
|
1d34e32431 | ||
|
|
b9d8091d0e | ||
|
|
9e040b7cd8 | ||
|
|
2323ef9182 | ||
|
|
c59af52e84 | ||
|
|
89755ae67f | ||
|
|
f92a0d4d16 | ||
|
|
bd651d1a67 | ||
|
|
c3dcb590b8 | ||
|
|
18ceb7055b | ||
|
|
a7a1a38df4 | ||
|
|
eea0118654 | ||
|
|
a4dbc73e8a | ||
|
|
b2d4fc06fc | ||
|
|
ce6c10172b | ||
|
|
b4acd028b6 | ||
|
|
ea9708092e | ||
|
|
9511f60f01 | ||
|
|
69f3eb2c96 | ||
|
|
285683d203 | ||
|
|
7aca1cae34 | ||
|
|
50073ed5d6 | ||
|
|
3f8d34ca83 | ||
|
|
94d8246272 | ||
|
|
d915a52eb6 | ||
|
|
aa4d19a05c | ||
|
|
1a7403bb74 | ||
|
|
0bc15941c2 | ||
|
|
7067d69bcc | ||
|
|
3793830ed9 | ||
|
|
09bbe7215a | ||
|
|
0fb80c303a | ||
|
|
9597771fe4 | ||
|
|
7db57bf6b2 | ||
|
|
6913521911 | ||
|
|
b0edec61ac | ||
|
|
e1199ecf10 | ||
|
|
1b82e9af5c | ||
|
|
ad6178bb08 | ||
|
|
f9589d2f23 | ||
|
|
deaeaac469 | ||
|
|
37b0f33545 | ||
|
|
43d4a6fa31 | ||
|
|
0f14fdea0c | ||
|
|
d99e9083cb | ||
|
|
d80e2476c7 | ||
|
|
b181b581aa | ||
|
|
d86020ac4f | ||
|
|
d0a5bf34f7 | ||
|
|
2bb179e124 | ||
|
|
ccc85ea0da | ||
|
|
04b7cc4df0 | ||
|
|
c17fd70de9 | ||
|
|
3417bc2f25 | ||
|
|
f45a83d7fc | ||
|
|
6e8085b425 | ||
|
|
7b0f9a7d9b | ||
|
|
070c78af5d | ||
|
|
affa870cc2 | ||
|
|
5ed284a15e | ||
|
|
d25cba4f64 | ||
|
|
65114ca015 | ||
|
|
ad79ecdf96 | ||
|
|
8c1c7488b2 | ||
|
|
d6cbbc51ab | ||
|
|
62b5f42d81 | ||
|
|
9e76b1181b | ||
|
|
ffae48d750 | ||
|
|
01d6be4d51 | ||
|
|
c1c32d65af | ||
|
|
be86596bb9 | ||
|
|
b1442e04d1 | ||
|
|
d509ac25f9 | ||
|
|
be6aa53cdb | ||
|
|
69cbec4afb | ||
|
|
2a05f05f44 | ||
|
|
1695151267 | ||
|
|
6638ea9ca3 | ||
|
|
52b25293e2 | ||
|
|
951335e102 | ||
|
|
c3602e159c | ||
|
|
9102af6afb | ||
|
|
c4ccb078a5 | ||
|
|
a32c1e41cc | ||
|
|
36db6bcf54 | ||
|
|
ca25c15d56 | ||
|
|
7c6c843965 | ||
|
|
c35e53436b | ||
|
|
117c46d9eb | ||
|
|
1dd46fafbd | ||
|
|
3ce10935f0 | ||
|
|
0ef015b253 | ||
|
|
6c62e7257f | ||
|
|
b9be45e421 | ||
|
|
6e73143de8 | ||
|
|
a592104acd | ||
|
|
93afa230a4 | ||
|
|
c53b408f28 | ||
|
|
491cbd6a7c | ||
|
|
b473d0ae86 | ||
|
|
47d3bd3b31 | ||
|
|
33b3a6905d | ||
|
|
f9e54e0ea5 | ||
|
|
912ca7701d | ||
|
|
179977a0da | ||
|
|
fcb347b90a | ||
|
|
1145a0706c | ||
|
|
fa2e701e23 | ||
|
|
2a5b3cdf82 | ||
|
|
66e18f04d8 | ||
|
|
f01fa458d8 | ||
|
|
aaff82afe5 | ||
|
|
22a0d67c0f | ||
|
|
6b344d7816 | ||
|
|
4187068cad | ||
|
|
98243ccca4 | ||
|
|
96e97ed2ce | ||
|
|
5fc400ccdb | ||
|
|
cda363a036 | ||
|
|
c327c0de5d | ||
|
|
2c9c200494 | ||
|
|
c114565bfa | ||
|
|
113872af6f | ||
|
|
3526716a5b | ||
|
|
37936bebbf | ||
|
|
04b9147e15 | ||
|
|
ff380c2558 | ||
|
|
75aebda809 | ||
|
|
3a01840390 | ||
|
|
cff638a43a | ||
|
|
d5f5b2f766 | ||
|
|
5320bff32c | ||
|
|
349e4c4a2f | ||
|
|
c9f9e547d6 | ||
|
|
72521a1c17 | ||
|
|
d32bab27bb |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,3 +32,6 @@ tests/*.out
|
||||
# Python cache files
|
||||
######################
|
||||
__pycache__/
|
||||
|
||||
# Customized Makefile overrides
|
||||
GNUmakefile
|
||||
|
||||
@@ -7,7 +7,7 @@ before_script:
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-arm-none-eabi qemu-system
|
||||
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-arm-none-eabi qemu-system mingw32
|
||||
|
||||
script:
|
||||
- make -C unix CC=gcc-4.7
|
||||
@@ -15,7 +15,11 @@ script:
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm
|
||||
- make -C stmhal
|
||||
- make -C stmhal BOARD=STM32F4DISC
|
||||
- make -C teensy
|
||||
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
|
||||
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.3 ./run-tests)
|
||||
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff $testbase.exp $testbase.out; done)
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Damien P. George
|
||||
Copyright (c) 2013, 2014 Damien P. George
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
23
README.md
23
README.md
@@ -11,26 +11,31 @@ The Micro Python project
|
||||
This is the Micro Python project, which aims to put an implementation
|
||||
of Python 3.x on a microcontroller.
|
||||
|
||||
WARNING: this project is in its early stages and is subject to large
|
||||
WARNING: this project is in early beta stage and is subject to large
|
||||
changes of the code-base, including project-wide name changes and API
|
||||
changes.
|
||||
|
||||
Micro Python implements the entire Python 3.4 syntax (including exceptions,
|
||||
"with", "yield from", etc.). The following core datatypes are provided:
|
||||
str (no Unicode support yet), bytes, bytearray, tuple, list, dict, set,
|
||||
array.array, collections.namedtuple, classes and instances. Builtin
|
||||
modules include sys, time, and struct. Note that only subset of
|
||||
Python 3.4 functionality implemented for the data types and modules.
|
||||
|
||||
See the repository www.github.com/micropython/pyboard for the Micro
|
||||
Python board.
|
||||
Python board, the officially supported reference electronic circuit board.
|
||||
|
||||
Major components in this repository:
|
||||
- py/ -- the core Python implementation, including compiler and runtime.
|
||||
- unix/ -- a version of Micro Python that runs on Unix.
|
||||
- stmhal/ -- a version of Micro Python that runs on the Micro Python board
|
||||
with an STM32F405RG (using ST's new Cube HAL drivers).
|
||||
with an STM32F405RG (using ST's Cube HAL drivers).
|
||||
- teensy/ -- a version of Micro Python that runs on the Teensy 3.1
|
||||
(preliminary but functional).
|
||||
|
||||
Additional components:
|
||||
- bare-arm/ -- a bare minimum version of Micro Python for ARM MCUs. Start
|
||||
with this if you want to port Micro Python to another microcontroller.
|
||||
- stm/ -- obsolete version of Micro Python for the Micro Python board
|
||||
that uses ST's old peripheral drivers.
|
||||
- unix-cpy/ -- a version of Micro Python that outputs bytecode (for testing).
|
||||
- tests/ -- test framework and test scripts.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
@@ -81,6 +86,10 @@ on the bottom left of the board, second row from the bottom).
|
||||
|
||||
Then to flash the code via USB DFU to your device:
|
||||
|
||||
$ dfu-util -a 0 -D build/flash.dfu
|
||||
$ make deploy
|
||||
|
||||
You will need the dfu-util program, on Arch Linux it's dfu-util-git in the AUR.
|
||||
You will need the dfu-util program, on Arch Linux it's dfu-util-git in the
|
||||
AUR. If the above does not work it may be because you don't have the
|
||||
correct permissions. Try then:
|
||||
|
||||
$ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV10/firmware.dfu
|
||||
|
||||
@@ -13,7 +13,7 @@ INC += -I$(PY_SRC)
|
||||
INC += -I$(BUILD)
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
@@ -22,7 +22,7 @@ else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
LDFLAGS = --nostdlib -T stm32f405.ld
|
||||
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
|
||||
LIBS =
|
||||
|
||||
SRC_C = \
|
||||
@@ -38,9 +38,9 @@ SRC_S = \
|
||||
|
||||
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
|
||||
|
||||
all: $(BUILD)/flash.elf
|
||||
all: $(BUILD)/firmware.elf
|
||||
|
||||
$(BUILD)/flash.elf: $(OBJ)
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
@@ -53,7 +53,6 @@ void do_str(const char *src) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
qstr_init();
|
||||
mp_init();
|
||||
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\n')");
|
||||
mp_deinit();
|
||||
|
||||
@@ -2,41 +2,53 @@
|
||||
|
||||
// options to control how Micro Python is built
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (512)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
#define MICROPY_ENABLE_REPL_HELPERS (0)
|
||||
#define MICROPY_ENABLE_LEXER_UNIX (0)
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_ENABLE_MOD_COLLECTIONS (0)
|
||||
#define MICROPY_ENABLE_MOD_MATH (0)
|
||||
#define MICROPY_ENABLE_MOD_CMATH (0)
|
||||
#define MICROPY_ENABLE_MOD_IO (0)
|
||||
#define MICROPY_ENABLE_MOD_STRUCT (0)
|
||||
#define MICROPY_ENABLE_MOD_SYS (0)
|
||||
#define MICROPY_ENABLE_PROPERTY (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
||||
#define MICROPY_PY_GC (0)
|
||||
#define MICROPY_PY_ARRAY (0)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_IO (0)
|
||||
#define MICROPY_PY_STRUCT (0)
|
||||
#define MICROPY_PY_SYS (0)
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_PATH_MAX (512)
|
||||
|
||||
//#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define BYTES_PER_WORD (4)
|
||||
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
|
||||
#define UINT_FMT "%lu"
|
||||
#define INT_FMT "%ld"
|
||||
|
||||
typedef int32_t machine_int_t; // must be pointer size
|
||||
typedef uint32_t machine_uint_t; // must be pointer size
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
|
||||
#define MICROPY_EXTRA_BUILTINS \
|
||||
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
4
examples/SDdatalogger/README.md
Normal file
4
examples/SDdatalogger/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
This is a SDdatalogger, to log data from the accelerometer to the SD-card. It also functions as card reader, so you can easily get the data on your PC.
|
||||
|
||||
To run, put the boot.py, cardreader.py and datalogger.py files on either the flash or the SD-card of your pyboard.
|
||||
Upon reset, the datalogger script is run and logs the data. If you press the user button after reset and hold it until the orange LED goes out, you enter the cardreader mode and the filesystem is mounted to your PC.
|
||||
25
examples/SDdatalogger/boot.py
Normal file
25
examples/SDdatalogger/boot.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# boot.py -- runs on boot-up
|
||||
# Let's you choose which script to run.
|
||||
# > To run 'datalogger.py':
|
||||
# * press reset and do nothing else
|
||||
# > To run 'cardreader.py':
|
||||
# * press reset
|
||||
# * press user switch and hold until orange LED goes out
|
||||
|
||||
import pyb
|
||||
|
||||
pyb.LED(3).on() # indicate we are waiting for switch press
|
||||
pyb.delay(2000) # wait for user to maybe press the switch
|
||||
switch_value = pyb.Switch()() # sample the switch at end of delay
|
||||
pyb.LED(3).off() # indicate that we finished waiting for the switch
|
||||
|
||||
pyb.LED(4).on() # indicate that we are selecting the mode
|
||||
|
||||
if switch_value:
|
||||
pyb.usb_mode('CDC+MSC')
|
||||
pyb.main('cardreader.py') # if switch was pressed, run this
|
||||
else:
|
||||
pyb.usb_mode('CDC+HID')
|
||||
pyb.main('datalogger.py') # if switch wasn't pressed, run this
|
||||
|
||||
pyb.LED(4).off() # indicate that we finished selecting the mode
|
||||
2
examples/SDdatalogger/cardreader.py
Normal file
2
examples/SDdatalogger/cardreader.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# cardread.py
|
||||
# This is called when the user enters cardreader mode. It does nothing.
|
||||
33
examples/SDdatalogger/datalogger.py
Normal file
33
examples/SDdatalogger/datalogger.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# datalogger.py
|
||||
# Logs the data from the acceleromter to a file on the SD-card
|
||||
|
||||
import pyb
|
||||
|
||||
# creating objects
|
||||
accel = pyb.Accel()
|
||||
blue = pyb.LED(4)
|
||||
switch = pyb.Switch()
|
||||
|
||||
# loop
|
||||
while True:
|
||||
|
||||
# wait for interrupt
|
||||
# this reduces power consumption while waiting for switch press
|
||||
pyb.wfi()
|
||||
|
||||
# start if switch is pressed
|
||||
if switch():
|
||||
pyb.delay(200) # delay avoids detection of multiple presses
|
||||
blue.on() # blue LED indicates file open
|
||||
log = open('1:/log.csv', 'w') # open file on SD (SD: '1:/', flash: '0/)
|
||||
|
||||
# until switch is pressed again
|
||||
while not switch():
|
||||
t = pyb.millis() # get time
|
||||
x, y, z = accel.filtered_xyz() # get acceleration data
|
||||
log.write('{},{},{},{}\n'.format(t,x,y,z)) # write data to file
|
||||
|
||||
# end after switch is pressed again
|
||||
log.close() # close file
|
||||
blue.off() # blue LED indicates file closed
|
||||
pyb.delay(200) # delay avoids detection of multiple presses
|
||||
@@ -1,14 +1,17 @@
|
||||
# log the accelerometer values to a file, 1 per second
|
||||
# log the accelerometer values to a .csv-file on the SD-card
|
||||
|
||||
f = open('motion.dat', 'w') # open the file for writing
|
||||
import pyb
|
||||
|
||||
for i in range(60): # loop 60 times
|
||||
time = pyb.time() # get the current time
|
||||
accel = pyb.accel() # get the accelerometer data
|
||||
accel = pyb.Accel() # create object of accelerometer
|
||||
blue = pyb.LED(4) # create object of blue LED
|
||||
|
||||
# write time and x,y,z values to the file
|
||||
f.write('{} {} {} {}\n'.format(time, accel[0], accel[1], accel[2]))
|
||||
log = open('1:/log.csv', 'w') # open file to write data - 1:/ ist the SD-card, 0:/ the internal memory
|
||||
blue.on() # turn on blue LED
|
||||
|
||||
pyb.delay(1000) # wait 1000 ms = 1 second
|
||||
for i in range(100): # do 100 times (if the board is connected via USB, you can't write longer because the PC tries to open the filesystem which messes up your file.)
|
||||
t = pyb.millis() # get time since reset
|
||||
x, y, z = accel.filtered_xyz() # get acceleration data
|
||||
log.write('{},{},{},{}\n'.format(t,x,y,z)) # write data to file
|
||||
|
||||
f.close() # close the file
|
||||
log.close() # close file
|
||||
blue.off() # turn off LED
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import pyb
|
||||
|
||||
def led_angle(seconds_to_run_for):
|
||||
# make LED objects
|
||||
l1 = pyb.Led(1)
|
||||
l2 = pyb.Led(2)
|
||||
l1 = pyb.LED(1)
|
||||
l2 = pyb.LED(2)
|
||||
accel = pyb.Accel()
|
||||
|
||||
for i in range(20 * seconds_to_run_for):
|
||||
# get x-axis
|
||||
accel = pyb.accel()[0]
|
||||
x = accel.x()
|
||||
|
||||
# turn on LEDs depending on angle
|
||||
if accel < -10:
|
||||
if x < -10:
|
||||
l1.on()
|
||||
l2.off()
|
||||
elif accel > 10:
|
||||
elif x > 10:
|
||||
l1.off()
|
||||
l2.on()
|
||||
else:
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
def nodecor(x):
|
||||
return x
|
||||
|
||||
byte_code = native = viper = nodecor
|
||||
bytecode = native = viper = nodecor
|
||||
|
||||
58
examples/pins.py
Normal file
58
examples/pins.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# Print a nice list of pins, their current settings, and available afs.
|
||||
# Requires pins_af.py from stmhal/build-PYBV10/ directory.
|
||||
|
||||
import pyb
|
||||
import pins_af
|
||||
|
||||
def af():
|
||||
max_name_width = 0
|
||||
max_af_width = 0
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
max_name_width = max(max_name_width, len(pin_entry[0]))
|
||||
for af_entry in pin_entry[1:]:
|
||||
max_af_width = max(max_af_width, len(af_entry[1]))
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
pin_name = pin_entry[0]
|
||||
print('%-*s ' % (max_name_width, pin_name), end='')
|
||||
for af_entry in pin_entry[1:]:
|
||||
print('%2d: %-*s ' % (af_entry[0], max_af_width, af_entry[1]), end='')
|
||||
print('')
|
||||
|
||||
def pins():
|
||||
mode_str = { pyb.Pin.IN : 'IN',
|
||||
pyb.Pin.OUT_PP : 'OUT_PP',
|
||||
pyb.Pin.OUT_OD : 'OUT_OD',
|
||||
pyb.Pin.AF_PP : 'AF_PP',
|
||||
pyb.Pin.AF_OD : 'AF_OD',
|
||||
pyb.Pin.ANALOG : 'ANALOG' }
|
||||
pull_str = { pyb.Pin.PULL_NONE : '',
|
||||
pyb.Pin.PULL_UP : 'PULL_UP',
|
||||
pyb.Pin.PULL_DOWN : 'PULL_DOWN' }
|
||||
width = [0, 0, 0, 0]
|
||||
rows = []
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
row = []
|
||||
pin_name = pin_entry[0]
|
||||
pin = pyb.Pin(pin_name)
|
||||
pin_mode = pin.mode()
|
||||
row.append(pin_name)
|
||||
row.append(mode_str[pin_mode])
|
||||
row.append(pull_str[pin.pull()])
|
||||
if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD:
|
||||
pin_af = pin.af()
|
||||
for af_entry in pin_entry[1:]:
|
||||
if pin_af == af_entry[0]:
|
||||
af_str = '%d: %s' % (pin_af, af_entry[1])
|
||||
break
|
||||
else:
|
||||
af_str = '%d' % pin_af
|
||||
else:
|
||||
af_str = ''
|
||||
row.append(af_str)
|
||||
for col in range(len(width)):
|
||||
width[col] = max(width[col], len(row[col]))
|
||||
rows.append(row)
|
||||
for row in rows:
|
||||
for col in range(len(width)):
|
||||
print('%-*s ' % (width[col], row[col]), end='')
|
||||
print('')
|
||||
45
examples/switch.py
Normal file
45
examples/switch.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
switch.py
|
||||
=========
|
||||
|
||||
Light up some leds when the USR switch on the pyboard is pressed.
|
||||
|
||||
Example Usage::
|
||||
|
||||
Micro Python v1.0.1 on 2014-05-12; PYBv1.0 with STM32F405RG
|
||||
Type "help()" for more information.
|
||||
>>> import switch
|
||||
>>> switch.run_loop()
|
||||
Loop started.
|
||||
Press Ctrl+C to break out of the loop.
|
||||
|
||||
"""
|
||||
|
||||
import pyb
|
||||
|
||||
switch = pyb.Switch()
|
||||
red_led = pyb.LED(1)
|
||||
green_led = pyb.LED(2)
|
||||
orange_led = pyb.LED(3)
|
||||
blue_led = pyb.LED(4)
|
||||
all_leds = (red_led, green_led, orange_led, blue_led)
|
||||
|
||||
def run_loop(leds=all_leds):
|
||||
"""
|
||||
Start the loop.
|
||||
|
||||
:param `leds`: Which LEDs to light up upon switch press.
|
||||
:type `leds`: sequence of LED objects
|
||||
"""
|
||||
print('Loop started.\nPress Ctrl+C to break out of the loop.')
|
||||
while 1:
|
||||
try:
|
||||
if switch():
|
||||
[led.on() for led in leds]
|
||||
else:
|
||||
[led.off() for led in leds]
|
||||
except OSError: # VCPInterrupt # Ctrl+C in interpreter mode.
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_loop()
|
||||
595
extmod/miniz/tinfl.c
Normal file
595
extmod/miniz/tinfl.c
Normal file
@@ -0,0 +1,595 @@
|
||||
/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
|
||||
See "unlicense" statement at the end of this file.
|
||||
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
|
||||
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
|
||||
|
||||
The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
|
||||
*/
|
||||
#ifndef TINFL_HEADER_INCLUDED
|
||||
#define TINFL_HEADER_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char mz_uint8;
|
||||
typedef signed short mz_int16;
|
||||
typedef unsigned short mz_uint16;
|
||||
typedef unsigned int mz_uint32;
|
||||
typedef unsigned int mz_uint;
|
||||
typedef unsigned long long mz_uint64;
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
|
||||
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
|
||||
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
|
||||
#define MINIZ_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
||||
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
|
||||
#define MINIZ_HAS_64BIT_REGISTERS 1
|
||||
#endif
|
||||
|
||||
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
|
||||
#ifdef _MSC_VER
|
||||
#define MZ_MACRO_END while (0, 0)
|
||||
#else
|
||||
#define MZ_MACRO_END while (0)
|
||||
#endif
|
||||
|
||||
// Decompression flags used by tinfl_decompress().
|
||||
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
|
||||
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
|
||||
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
|
||||
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
|
||||
enum
|
||||
{
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
||||
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
||||
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
||||
};
|
||||
|
||||
// High level decompression functions:
|
||||
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
|
||||
// On entry:
|
||||
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
|
||||
// On return:
|
||||
// Function returns a pointer to the decompressed data, or NULL on failure.
|
||||
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
|
||||
// The caller must free() the returned block when it's no longer needed.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
|
||||
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
|
||||
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
|
||||
// Returns 1 on success or 0 on failure.
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
|
||||
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
||||
|
||||
// Max size of LZ dictionary.
|
||||
#define TINFL_LZ_DICT_SIZE 32768
|
||||
|
||||
// Return status.
|
||||
typedef enum
|
||||
{
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
||||
} tinfl_status;
|
||||
|
||||
// Initializes the decompressor to its initial state.
|
||||
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
|
||||
#define tinfl_get_adler32(r) (r)->m_check_adler32
|
||||
|
||||
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
|
||||
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
|
||||
|
||||
// Internal/private bits follow.
|
||||
// dpgeorge: TINFL_FAST_LOOKUP_BITS can be adjusted to trade off RAM usage against speed.
|
||||
enum
|
||||
{
|
||||
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
|
||||
TINFL_FAST_LOOKUP_BITS = 7, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
|
||||
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
|
||||
} tinfl_huff_table;
|
||||
|
||||
#if MINIZ_HAS_64BIT_REGISTERS
|
||||
#define TINFL_USE_64BIT_BITBUF 1
|
||||
#endif
|
||||
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
typedef mz_uint64 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (64)
|
||||
#else
|
||||
typedef mz_uint32 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (32)
|
||||
#endif
|
||||
|
||||
struct tinfl_decompressor_tag
|
||||
{
|
||||
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
|
||||
tinfl_bit_buf_t m_bit_buf;
|
||||
size_t m_dist_from_out_buf_start;
|
||||
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
|
||||
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
|
||||
};
|
||||
|
||||
#endif // #ifdef TINFL_HEADER_INCLUDED
|
||||
|
||||
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
|
||||
|
||||
#ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
|
||||
#ifdef MINIZ_NO_MALLOC
|
||||
#define MZ_MALLOC(x) NULL
|
||||
#define MZ_FREE(x) x, ((void)0)
|
||||
#define MZ_REALLOC(p, x) NULL
|
||||
#else
|
||||
#define MZ_MALLOC(x) malloc(x)
|
||||
#define MZ_FREE(x) free(x)
|
||||
#define MZ_REALLOC(p, x) realloc(p, x)
|
||||
#endif
|
||||
|
||||
#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
|
||||
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
|
||||
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
|
||||
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
|
||||
#else
|
||||
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
|
||||
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
||||
#endif
|
||||
|
||||
#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
|
||||
#define TINFL_MEMSET(p, c, l) memset(p, c, l)
|
||||
|
||||
#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
|
||||
#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
|
||||
#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
|
||||
#define TINFL_CR_FINISH }
|
||||
|
||||
// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
|
||||
// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
|
||||
#define TINFL_GET_BYTE(state_index, c) do { \
|
||||
if (pIn_buf_cur >= pIn_buf_end) { \
|
||||
for ( ; ; ) { \
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
|
||||
TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
|
||||
if (pIn_buf_cur < pIn_buf_end) { \
|
||||
c = *pIn_buf_cur++; \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
c = 0; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else c = *pIn_buf_cur++; } MZ_MACRO_END
|
||||
|
||||
#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
|
||||
#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
|
||||
// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
|
||||
// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
|
||||
// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
|
||||
// bit buffer contains >=15 bits (deflate's max. Huffman code size).
|
||||
#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
|
||||
do { \
|
||||
temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
|
||||
if (temp >= 0) { \
|
||||
code_len = temp >> 9; \
|
||||
if ((code_len) && (num_bits >= code_len)) \
|
||||
break; \
|
||||
} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; \
|
||||
do { \
|
||||
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
|
||||
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
|
||||
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
|
||||
} while (num_bits < 15);
|
||||
|
||||
// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
|
||||
// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
|
||||
// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
|
||||
// The slow path is only executed at the very end of the input buffer.
|
||||
#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
|
||||
int temp; mz_uint code_len, c; \
|
||||
if (num_bits < 15) { \
|
||||
if ((pIn_buf_end - pIn_buf_cur) < 2) { \
|
||||
TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
|
||||
} else { \
|
||||
bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
|
||||
} \
|
||||
} \
|
||||
if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
|
||||
code_len = temp >> 9, temp &= 511; \
|
||||
else { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
|
||||
} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
|
||||
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
|
||||
{
|
||||
static const mz_uint16 s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
|
||||
static const mz_uint8 s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
|
||||
static const mz_uint16 s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
|
||||
static const mz_uint8 s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
|
||||
static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
|
||||
static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 };
|
||||
|
||||
tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
|
||||
const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
|
||||
mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
|
||||
size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
|
||||
|
||||
// Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
|
||||
if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
|
||||
|
||||
num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
|
||||
TINFL_CR_BEGIN
|
||||
|
||||
bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
|
||||
counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
|
||||
if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
|
||||
if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
|
||||
if (r->m_type == 0)
|
||||
{
|
||||
TINFL_SKIP_BITS(5, num_bits & 7);
|
||||
for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
|
||||
if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
|
||||
while ((counter) && (num_bits))
|
||||
{
|
||||
TINFL_GET_BITS(51, dist, 8);
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)dist;
|
||||
counter--;
|
||||
}
|
||||
while (counter)
|
||||
{
|
||||
size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
while (pIn_buf_cur >= pIn_buf_end)
|
||||
{
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
|
||||
{
|
||||
TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
|
||||
}
|
||||
}
|
||||
n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
|
||||
TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
|
||||
}
|
||||
}
|
||||
else if (r->m_type == 3)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r->m_type == 1)
|
||||
{
|
||||
mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
|
||||
r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
|
||||
for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
|
||||
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
|
||||
r->m_table_sizes[2] = 19;
|
||||
}
|
||||
for ( ; (int)r->m_type >= 0; r->m_type--)
|
||||
{
|
||||
int tree_next, tree_cur; tinfl_huff_table *pTable;
|
||||
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
|
||||
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
|
||||
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
|
||||
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
|
||||
if ((65536 != total) && (used_syms > 1))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
|
||||
}
|
||||
for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
|
||||
{
|
||||
mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
|
||||
cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
|
||||
if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
|
||||
if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
|
||||
rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
|
||||
for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
|
||||
{
|
||||
tree_cur -= ((rev_code >>= 1) & 1);
|
||||
if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
|
||||
}
|
||||
tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
|
||||
}
|
||||
if (r->m_type == 2)
|
||||
{
|
||||
for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
|
||||
{
|
||||
mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
|
||||
if ((dist == 16) && (!counter))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
|
||||
}
|
||||
num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
|
||||
TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
|
||||
}
|
||||
if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
|
||||
}
|
||||
TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
|
||||
}
|
||||
}
|
||||
for ( ; ; )
|
||||
{
|
||||
mz_uint8 *pSrc;
|
||||
for ( ; ; )
|
||||
{
|
||||
if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
|
||||
{
|
||||
TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
|
||||
if (counter >= 256)
|
||||
break;
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sym2; mz_uint code_len;
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
|
||||
#else
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
|
||||
if (counter & 256)
|
||||
break;
|
||||
|
||||
#if !TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
bit_buf >>= code_len; num_bits -= code_len;
|
||||
|
||||
pOut_buf_cur[0] = (mz_uint8)counter;
|
||||
if (sym2 & 256)
|
||||
{
|
||||
pOut_buf_cur++;
|
||||
counter = sym2;
|
||||
break;
|
||||
}
|
||||
pOut_buf_cur[1] = (mz_uint8)sym2;
|
||||
pOut_buf_cur += 2;
|
||||
}
|
||||
}
|
||||
if ((counter &= 511) == 256) break;
|
||||
|
||||
num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
|
||||
|
||||
TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
|
||||
num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
|
||||
|
||||
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
|
||||
if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
|
||||
}
|
||||
|
||||
pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
|
||||
|
||||
if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
|
||||
{
|
||||
while (counter--)
|
||||
{
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
|
||||
else if ((counter >= 9) && (counter <= dist))
|
||||
{
|
||||
const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
|
||||
do
|
||||
{
|
||||
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
|
||||
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
|
||||
pOut_buf_cur += 8;
|
||||
} while ((pSrc += 8) < pSrc_end);
|
||||
if ((counter &= 7) < 3)
|
||||
{
|
||||
if (counter)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if (counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
do
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur[2] = pSrc[2];
|
||||
pOut_buf_cur += 3; pSrc += 3;
|
||||
} while ((int)(counter -= 3) > 2);
|
||||
if ((int)counter > 0)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if ((int)counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!(r->m_final & 1));
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
|
||||
}
|
||||
TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
|
||||
TINFL_CR_FINISH
|
||||
|
||||
common_exit:
|
||||
r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
|
||||
*pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
|
||||
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
|
||||
{
|
||||
const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
|
||||
mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
|
||||
while (buf_len)
|
||||
{
|
||||
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
|
||||
{
|
||||
s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
|
||||
s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
|
||||
}
|
||||
for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
|
||||
s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
|
||||
}
|
||||
r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Higher level helper functions.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
|
||||
*pOut_len = 0;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
|
||||
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
src_buf_ofs += src_buf_size;
|
||||
*pOut_len += dst_buf_size;
|
||||
if (status == TINFL_STATUS_DONE) break;
|
||||
new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
|
||||
pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
|
||||
if (!pNew_buf)
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
|
||||
status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
|
||||
}
|
||||
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
|
||||
{
|
||||
int result = 0;
|
||||
tinfl_decompressor decomp;
|
||||
mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
|
||||
if (!pDict)
|
||||
return TINFL_STATUS_FAILED;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
|
||||
(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
|
||||
in_buf_ofs += in_buf_size;
|
||||
if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
|
||||
break;
|
||||
if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
|
||||
{
|
||||
result = (status == TINFL_STATUS_DONE);
|
||||
break;
|
||||
}
|
||||
dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
|
||||
}
|
||||
MZ_FREE(pDict);
|
||||
*pIn_buf_size = in_buf_ofs;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
634
extmod/moductypes.c
Normal file
634
extmod/moductypes.c
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "objtuple.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
/// \module uctypes - Access data structures in memory
|
||||
///
|
||||
/// The module allows to define layout of raw data structure (using terms
|
||||
/// of C language), and then access memory buffers using this definition.
|
||||
/// The module also provides convenience functions to access memory buffers
|
||||
/// contained in Python objects or wrap memory buffers in Python objects.
|
||||
/// \constant UINT8_1 - uint8_t value type
|
||||
|
||||
/// \class struct - C-like structure
|
||||
///
|
||||
/// Encapsulalation of in-memory data structure. This class doesn't define
|
||||
/// any methods, only attribute access (for structure fields) and
|
||||
/// indexing (for pointer and array fields).
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// # Define layout of a structure with 2 fields
|
||||
/// # 0 and 4 are byte offsets of fields from the beginning of struct
|
||||
/// # they are logically ORed with field type
|
||||
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
|
||||
///
|
||||
/// # Example memory buffer to access (contained in bytes object)
|
||||
/// buf = b"\x64\0\0\0\0x14"
|
||||
///
|
||||
/// # Create structure object referring to address of
|
||||
/// # the data in the buffer above
|
||||
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
|
||||
///
|
||||
/// # Access fields
|
||||
/// print(s.a, s.b)
|
||||
/// # Result:
|
||||
/// # 100, 20
|
||||
|
||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||
#define LAYOUT_BIG_ENDIAN (1)
|
||||
#define LAYOUT_NATIVE (2)
|
||||
|
||||
#define VAL_TYPE_BITS 4
|
||||
#define BITF_LEN_BITS 5
|
||||
#define BITF_OFF_BITS 5
|
||||
#define OFFSET_BITS 17
|
||||
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
||||
#error Invalid encoding field length
|
||||
#endif
|
||||
|
||||
enum {
|
||||
UINT8, INT8, UINT16, INT16,
|
||||
UINT32, INT32, UINT64, INT64,
|
||||
|
||||
BFUINT8, BFINT8, BFUINT16, BFINT16,
|
||||
BFUINT32, BFINT32,
|
||||
|
||||
FLOAT32, FLOAT64,
|
||||
};
|
||||
|
||||
#define AGG_TYPE_BITS 2
|
||||
|
||||
enum {
|
||||
STRUCT, PTR, ARRAY, BITFIELD,
|
||||
};
|
||||
|
||||
// Here we need to set sign bit right
|
||||
#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)
|
||||
#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1));
|
||||
// Bit 0 is "is_signed"
|
||||
#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
|
||||
#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type;
|
||||
|
||||
typedef struct _mp_obj_uctypes_struct_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t desc;
|
||||
byte *addr;
|
||||
uint32_t flags;
|
||||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
STATIC NORETURN void syntax_error() {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "syntax error in uctypes descriptor"));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
if (n_args < 2 || n_args > 3) {
|
||||
syntax_error();
|
||||
}
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = type_in;
|
||||
o->desc = args[0];
|
||||
o->addr = (void*)mp_obj_get_int(args[1]);
|
||||
o->flags = LAYOUT_NATIVE;
|
||||
if (n_args == 3) {
|
||||
o->flags = mp_obj_get_int(args[2]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
const char *typen = "unk";
|
||||
if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
typen = "STRUCT";
|
||||
} else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
switch (agg_type) {
|
||||
case PTR: typen = "PTR"; break;
|
||||
case ARRAY: typen = "ARRAY"; break;
|
||||
}
|
||||
} else {
|
||||
typen = "ERROR";
|
||||
}
|
||||
print(env, "<struct %s %p>", typen, self->addr);
|
||||
}
|
||||
|
||||
static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
|
||||
if (val_type == FLOAT32) {
|
||||
return 4;
|
||||
} else {
|
||||
return GET_SCALAR_SIZE(val_type & 7);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size) {
|
||||
mp_obj_dict_t *d = desc_in;
|
||||
mp_uint_t total_size = 0;
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict)) {
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
for (mp_uint_t i = 0; i < d->map.alloc; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) {
|
||||
mp_obj_t v = d->map.table[i].value;
|
||||
if (MP_OBJ_IS_SMALL_INT(v)) {
|
||||
mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t s = uctypes_struct_scalar_size(val_type);
|
||||
if (s > *max_field_size) {
|
||||
*max_field_size = s;
|
||||
}
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
} else {
|
||||
if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) {
|
||||
syntax_error();
|
||||
}
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)v;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_uint_t s = uctypes_struct_size(t->items[1], max_field_size);
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTR: {
|
||||
if (offset + sizeof(void*) > total_size) {
|
||||
total_size = offset + sizeof(void*);
|
||||
}
|
||||
if (sizeof(void*) > *max_field_size) {
|
||||
*max_field_size = sizeof(void*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARRAY: {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
} else {
|
||||
item_s = uctypes_struct_size(t->items[2], max_field_size);
|
||||
}
|
||||
|
||||
mp_uint_t byte_sz = item_s * arr_sz;
|
||||
if (offset + byte_sz > total_size) {
|
||||
total_size = offset + byte_sz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Round size up to alignment of biggest field
|
||||
total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
|
||||
mp_uint_t max_field_size = 0;
|
||||
if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) {
|
||||
mp_obj_uctypes_struct_t *obj = obj_in;
|
||||
obj_in = obj->desc;
|
||||
}
|
||||
mp_uint_t size = uctypes_struct_size(obj_in, &max_field_size);
|
||||
return MP_OBJ_NEW_SMALL_INT(size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_sizeof_obj, uctypes_struct_sizeof);
|
||||
|
||||
STATIC inline mp_obj_t get_unaligned(uint val_type, void *p, int big_endian) {
|
||||
mp_int_t val = mp_binary_get_int(GET_SCALAR_SIZE(val_type), val_type & 1, big_endian, p);
|
||||
if (val_type == UINT32) {
|
||||
return mp_obj_new_int_from_uint(val);
|
||||
} else {
|
||||
return mp_obj_new_int(val);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC inline void set_unaligned(uint val_type, void *p, int big_endian, mp_obj_t val) {
|
||||
char struct_type = big_endian ? '>' : '<';
|
||||
static const char type2char[8] = "BbHhIiQq";
|
||||
mp_binary_set_val(struct_type, type2char[val_type], val, (byte**)&p);
|
||||
}
|
||||
|
||||
static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
return *(uint8_t*)p;
|
||||
case UINT16:
|
||||
return *(uint16_t*)p;
|
||||
case UINT32:
|
||||
return *(uint32_t*)p;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
*(uint8_t*)p = (uint8_t)v; return;
|
||||
case UINT16:
|
||||
*(uint16_t*)p = (uint16_t)v; return;
|
||||
case UINT32:
|
||||
*(uint32_t*)p = (uint32_t)v; return;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
return MP_OBJ_NEW_SMALL_INT(((uint8_t*)p)[index]);
|
||||
case INT8:
|
||||
return MP_OBJ_NEW_SMALL_INT(((int8_t*)p)[index]);
|
||||
case UINT16:
|
||||
return MP_OBJ_NEW_SMALL_INT(((uint16_t*)p)[index]);
|
||||
case INT16:
|
||||
return MP_OBJ_NEW_SMALL_INT(((int16_t*)p)[index]);
|
||||
case UINT32:
|
||||
return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
|
||||
case INT32:
|
||||
return mp_obj_new_int(((int32_t*)p)[index]);
|
||||
case UINT64:
|
||||
case INT64:
|
||||
return mp_obj_new_int_from_ll(((int64_t*)p)[index]);
|
||||
case FLOAT32:
|
||||
return mp_obj_new_float(((float*)p)[index]);
|
||||
case FLOAT64:
|
||||
return mp_obj_new_float(((double*)p)[index]);
|
||||
default:
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||
mp_int_t v = mp_obj_get_int(val);
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
((uint8_t*)p)[index] = (uint8_t)v; return;
|
||||
case INT8:
|
||||
((int8_t*)p)[index] = (int8_t)v; return;
|
||||
case UINT16:
|
||||
((uint16_t*)p)[index] = (uint16_t)v; return;
|
||||
case INT16:
|
||||
((int16_t*)p)[index] = (int16_t)v; return;
|
||||
case UINT32:
|
||||
((uint32_t*)p)[index] = (uint32_t)v; return;
|
||||
case INT32:
|
||||
((int32_t*)p)[index] = (int32_t)v; return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
|
||||
// TODO: Support at least OrderedDict in addition
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: no fields"));
|
||||
}
|
||||
|
||||
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
|
||||
if (MP_OBJ_IS_SMALL_INT(deref)) {
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
//printf("scalar type=%d offset=%x\n", val_type, offset);
|
||||
|
||||
if (val_type <= INT64) {
|
||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_aligned(val_type, self->addr + offset, 0);
|
||||
} else {
|
||||
set_aligned(val_type, self->addr + offset, 0, set_val);
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
} else {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_unaligned(val_type, self->addr + offset, self->flags);
|
||||
} else {
|
||||
set_unaligned(val_type, self->addr + offset, self->flags, set_val);
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
}
|
||||
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
||||
uint bit_offset = (offset >> 17) & 31;
|
||||
uint bit_len = (offset >> 22) & 31;
|
||||
offset &= (1 << 17) - 1;
|
||||
mp_uint_t val;
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
||||
} else {
|
||||
val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);
|
||||
}
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
val >>= bit_offset;
|
||||
val &= (1 << bit_len) - 1;
|
||||
// TODO: signed
|
||||
assert((val_type & 1) == 0);
|
||||
return mp_obj_new_int(val);
|
||||
} else {
|
||||
mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);
|
||||
mp_uint_t mask = (1 << bit_len) - 1;
|
||||
set_val_int &= mask;
|
||||
set_val_int <<= bit_offset;
|
||||
mask <<= bit_offset;
|
||||
val = (val & ~mask) | set_val_int;
|
||||
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
set_aligned_basic(val_type & 6, self->addr + offset, val);
|
||||
} else {
|
||||
mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
|
||||
self->addr + offset, (byte*)&val);
|
||||
}
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) {
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
if (set_val != MP_OBJ_NULL) {
|
||||
// Cannot assign to aggregate
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *sub = (mp_obj_tuple_t*)deref;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
//printf("agg type=%d offset=%x\n", agg_type, offset);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub->items[1];
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
case PTR: case ARRAY: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub;
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
//printf("PTR/ARR base addr=%p\n", o->addr);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
// Should be unreachable once all cases are handled
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
|
||||
*dest = val;
|
||||
}
|
||||
|
||||
STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) {
|
||||
return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
|
||||
if (value == MP_OBJ_NULL) {
|
||||
// delete
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: cannot index"));
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
|
||||
mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);
|
||||
|
||||
if (agg_type == ARRAY) {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
if (index >= arr_sz) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range"));
|
||||
}
|
||||
|
||||
if (t->len == 2) {
|
||||
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
|
||||
return get_unaligned(val_type, p, self->flags);
|
||||
} else {
|
||||
mp_uint_t dummy = 0;
|
||||
mp_uint_t size = uctypes_struct_size(t->items[2], &dummy);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = t->items[2];
|
||||
o->addr = self->addr + size * index;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
} else if (agg_type == PTR) {
|
||||
byte *p = *(void**)self->addr;
|
||||
if (MP_OBJ_IS_SMALL_INT(t->items[1])) {
|
||||
uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
|
||||
return get_aligned(val_type, p, index);
|
||||
} else {
|
||||
mp_uint_t dummy = 0;
|
||||
mp_uint_t size = uctypes_struct_size(t->items[1], &dummy);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = t->items[1];
|
||||
o->addr = p + size * index;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
} else {
|
||||
// store
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
/// \function addressof()
|
||||
/// Return address of object's data (applies to object providing buffer
|
||||
/// interface).
|
||||
mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
return mp_obj_new_int((mp_int_t)bufinfo.buf);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
||||
|
||||
/// \function bytearray_at()
|
||||
/// Capture memory at given address of given size as bytearray. Memory is
|
||||
/// captured by reference (and thus memory pointed by bytearray may change
|
||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
||||
mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytearray_by_ref(mp_obj_int_get(size), (void*)mp_obj_int_get(ptr));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||
|
||||
/// \function bytes_at()
|
||||
/// Capture memory at given address of given size as bytes. Memory is
|
||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
||||
/// ("zero copy").
|
||||
mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytes((void*)mp_obj_int_get(ptr), mp_obj_int_get(size));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_struct,
|
||||
.print = uctypes_struct_print,
|
||||
.make_new = uctypes_struct_make_new,
|
||||
.load_attr = uctypes_struct_load_attr,
|
||||
.store_attr = uctypes_struct_store_attr,
|
||||
.subscr = uctypes_struct_subscr,
|
||||
};
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uctypes_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uctypes) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&uctypes_struct_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sizeof), (mp_obj_t)&uctypes_struct_sizeof_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_addressof), (mp_obj_t)&uctypes_struct_addressof_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes_at), (mp_obj_t)&uctypes_struct_bytes_at_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray_at), (mp_obj_t)&uctypes_struct_bytearray_at_obj },
|
||||
|
||||
/// \moduleref uctypes
|
||||
|
||||
/// \constant NATIVE - Native structure layout - native endianness,
|
||||
/// platform-specific field alignment
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_NATIVE), MP_OBJ_NEW_SMALL_INT(LAYOUT_NATIVE) },
|
||||
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_LITTLE_ENDIAN) },
|
||||
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BIG_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_BIG_ENDIAN) },
|
||||
|
||||
/// \constant VOID - void value type, may be used only as pointer target type.
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_VOID), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
|
||||
/// \constant UINT8 - uint8_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, 4)) },
|
||||
/// \constant INT8 - int8_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT8, 4)) },
|
||||
/// \constant UINT16 - uint16_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
/// \constant INT16 - int16_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
/// \constant UINT32 - uint32_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
/// \constant INT32 - int32_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
/// \constant UINT64 - uint64_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
/// \constant INT64 - int64_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT32, 4)) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_POS), MP_OBJ_NEW_SMALL_INT(17) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_LEN), MP_OBJ_NEW_SMALL_INT(22) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PTR), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ARRAY), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uctypes_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uctypes_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uctypes,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uctypes_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
108
extmod/modzlibd.c
Normal file
108
extmod/modzlibd.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_ZLIBD
|
||||
|
||||
#include "miniz/tinfl.c"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
tinfl_decompressor *decomp = m_new_obj(tinfl_decompressor);
|
||||
tinfl_init(decomp);
|
||||
DEBUG_printf("sizeof(tinfl_decompressor)=" UINT_FMT "\n", sizeof(tinfl_decompressor));
|
||||
|
||||
byte *out = m_new(byte, bufinfo.len);
|
||||
size_t out_len = bufinfo.len;
|
||||
size_t in_buf_ofs = 0, dst_buf_ofs = 0;
|
||||
size_t dst_buf_sz = bufinfo.len;
|
||||
|
||||
while (1) {
|
||||
size_t in_buf_sz = bufinfo.len - in_buf_ofs;
|
||||
DEBUG_printf("tinfl in: in_ofs=%d in_sz=%d dst_ofs=%d, dst_sz=%d\n", in_buf_ofs, in_buf_sz, dst_buf_ofs, dst_buf_sz);
|
||||
tinfl_status st = tinfl_decompress(decomp,
|
||||
bufinfo.buf + in_buf_ofs, &in_buf_sz,
|
||||
out, out + dst_buf_ofs, &dst_buf_sz,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
DEBUG_printf("tinfl out: st=%d, in_sz=%d, out_sz=%d\n", st, in_buf_sz, dst_buf_sz);
|
||||
in_buf_ofs += in_buf_sz;
|
||||
dst_buf_ofs += dst_buf_sz;
|
||||
if (st != TINFL_STATUS_HAS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
out = m_renew(byte, out, out_len, dst_buf_ofs + 256);
|
||||
out_len = dst_buf_ofs + 256;
|
||||
dst_buf_sz = out_len - dst_buf_ofs;
|
||||
}
|
||||
|
||||
m_del_obj(tinfl_decompressor, decomp);
|
||||
return mp_obj_new_bytearray_by_ref(dst_buf_ofs, out);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_zlibd_decompress_obj, 1, 3, mod_zlibd_decompress);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_zlibd_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_zlibd) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_zlibd_decompress_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_zlibd_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_zlibd_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_zlibd = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_zlibd,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_zlibd_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_ZLIBD
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -77,3 +103,16 @@ void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_all
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "extra keyword arguments given"));
|
||||
}
|
||||
}
|
||||
|
||||
void mp_arg_parse_all_kw_array(uint n_pos, uint n_kw, const mp_obj_t *args, uint n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) {
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_pos);
|
||||
mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);
|
||||
}
|
||||
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
NORETURN void mp_arg_error_unimpl_kw(void) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
"keyword argument(s) not yet implemented - use normal args instead"));
|
||||
}
|
||||
#endif
|
||||
|
||||
327
py/asmarm.c
Normal file
327
py/asmarm.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Fabian Vogt
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmarm.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_ARM
|
||||
|
||||
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
|
||||
|
||||
struct _asm_arm_t {
|
||||
uint pass;
|
||||
uint code_offset;
|
||||
uint code_size;
|
||||
byte *code_base;
|
||||
byte dummy_data[4];
|
||||
|
||||
uint max_num_labels;
|
||||
int *label_offsets;
|
||||
int num_locals;
|
||||
uint push_reglist;
|
||||
uint stack_adjust;
|
||||
};
|
||||
|
||||
asm_arm_t *asm_arm_new(uint max_num_labels) {
|
||||
asm_arm_t *as;
|
||||
|
||||
as = m_new0(asm_arm_t, 1);
|
||||
as->max_num_labels = max_num_labels;
|
||||
as->label_offsets = m_new(int, max_num_labels);
|
||||
|
||||
return as;
|
||||
}
|
||||
|
||||
void asm_arm_free(asm_arm_t *as, bool free_code) {
|
||||
if (free_code) {
|
||||
m_del(byte, as->code_base, as->code_size);
|
||||
}
|
||||
|
||||
m_del_obj(asm_arm_t, as);
|
||||
}
|
||||
|
||||
void asm_arm_start_pass(asm_arm_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_ARM_PASS_COMPUTE) {
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as) {
|
||||
if (as->pass == ASM_ARM_PASS_COMPUTE) {
|
||||
// calculate size of code in bytes
|
||||
as->code_size = as->code_offset;
|
||||
as->code_base = m_new(byte, as->code_size);
|
||||
}
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit bytes
|
||||
// if as->pass < ASM_ARM_PASS_EMIT, then this function only returns a buffer of 4 bytes length
|
||||
STATIC byte *asm_arm_get_cur_to_write_bytes(asm_arm_t *as, int num_bytes_to_write) {
|
||||
if (as->pass < ASM_ARM_PASS_EMIT) {
|
||||
as->code_offset += num_bytes_to_write;
|
||||
return as->dummy_data;
|
||||
} else {
|
||||
assert(as->code_offset + num_bytes_to_write <= as->code_size);
|
||||
byte *c = as->code_base + as->code_offset;
|
||||
as->code_offset += num_bytes_to_write;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
uint asm_arm_get_code_size(asm_arm_t *as) {
|
||||
return as->code_size;
|
||||
}
|
||||
|
||||
void *asm_arm_get_code(asm_arm_t *as) {
|
||||
return as->code_base;
|
||||
}
|
||||
|
||||
// Insert word into instruction flow
|
||||
STATIC void emit(asm_arm_t *as, uint op) {
|
||||
*(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op;
|
||||
}
|
||||
|
||||
// Insert word into instruction flow, add "ALWAYS" condition code
|
||||
STATIC void emit_al(asm_arm_t *as, uint op) {
|
||||
emit(as, op | ARM_CC_AL);
|
||||
}
|
||||
|
||||
// Basic instructions without condition code
|
||||
STATIC uint asm_arm_op_push(uint reglist) {
|
||||
// stmfd sp!, {reglist}
|
||||
return 0x92d0000 | (reglist & 0xFFFF);
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_pop(uint reglist) {
|
||||
// ldmfd sp!, {reglist}
|
||||
return 0x8bd0000 | (reglist & 0xFFFF);
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_mov_reg(uint rd, uint rn) {
|
||||
// mov rd, rn
|
||||
return 0x1a00000 | (rd << 12) | rn;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_mov_imm(uint rd, uint imm) {
|
||||
// mov rd, #imm
|
||||
return 0x3a00000 | (rd << 12) | imm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) {
|
||||
// mvn rd, #imm
|
||||
return 0x3e00000 | (rd << 12) | imm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) {
|
||||
// add rd, rn, #imm
|
||||
return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) {
|
||||
// add rd, rn, rm
|
||||
return 0x0800000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) {
|
||||
// sub rd, rn, #imm
|
||||
return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
|
||||
}
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as) {
|
||||
// bkpt #0
|
||||
emit_al(as, 0x1200070);
|
||||
}
|
||||
|
||||
// locals:
|
||||
// - stored on the stack in ascending order
|
||||
// - numbered 0 through as->num_locals-1
|
||||
// - SP points to first local
|
||||
//
|
||||
// | SP
|
||||
// v
|
||||
// l0 l1 l2 ... l(n-1)
|
||||
// ^ ^
|
||||
// | low address | high address in RAM
|
||||
|
||||
void asm_arm_entry(asm_arm_t *as, int num_locals) {
|
||||
|
||||
if (num_locals < 0) {
|
||||
num_locals = 0;
|
||||
}
|
||||
|
||||
as->stack_adjust = 0;
|
||||
as->num_locals = num_locals;
|
||||
as->push_reglist = 1 << REG_R1 | 1 << REG_R2 | 1 << REG_R3 | 1 << REG_R4
|
||||
| 1 << REG_R5 | 1 << REG_R6 | 1 << REG_R7 | 1 << REG_R8;
|
||||
|
||||
// Only adjust the stack if there are more locals than usable registers
|
||||
if(num_locals > 3) {
|
||||
as->stack_adjust = num_locals * 4;
|
||||
// Align stack to 8 bytes
|
||||
if(as->num_locals & 1)
|
||||
as->stack_adjust += 4;
|
||||
}
|
||||
|
||||
emit_al(as, asm_arm_op_push(as->push_reglist | 1 << REG_LR));
|
||||
if (as->stack_adjust > 0) {
|
||||
emit_al(as, asm_arm_op_sub_imm(REG_SP, REG_SP, as->stack_adjust));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_exit(asm_arm_t *as) {
|
||||
if (as->stack_adjust > 0) {
|
||||
emit_al(as, asm_arm_op_add_imm(REG_SP, REG_SP, as->stack_adjust));
|
||||
}
|
||||
|
||||
emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << REG_PC)));
|
||||
}
|
||||
|
||||
void asm_arm_label_assign(asm_arm_t *as, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
if (as->pass < ASM_ARM_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(as->label_offsets[label] == -1);
|
||||
as->label_offsets[label] = as->code_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
|
||||
assert(as->label_offsets[label] == as->code_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_align(asm_arm_t* as, uint align) {
|
||||
// TODO fill unused data with NOPs?
|
||||
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
|
||||
}
|
||||
|
||||
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val) {
|
||||
byte *c = asm_arm_get_cur_to_write_bytes(as, bytesize);
|
||||
// only write to the buffer in the emit pass (otherwise we overflow dummy_data)
|
||||
if (as->pass == ASM_ARM_PASS_EMIT) {
|
||||
// little endian
|
||||
for (uint i = 0; i < bytesize; i++) {
|
||||
*c++ = val;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) {
|
||||
emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) {
|
||||
// TODO: There are more variants of immediate values
|
||||
if ((imm & 0xFF) == imm) {
|
||||
emit_al(as, asm_arm_op_mov_imm(rd, imm));
|
||||
} else if (imm < 0 && ((-imm) & 0xFF) == -imm) {
|
||||
emit_al(as, asm_arm_op_mvn_imm(rd, -imm));
|
||||
} else {
|
||||
//Insert immediate into code and jump over it
|
||||
emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc]
|
||||
emit_al(as, 0xa000000); // b pc
|
||||
emit(as, imm);
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) {
|
||||
// str rd, [sp, #local_num*4]
|
||||
emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) {
|
||||
// ldr rd, [sp, #local_num*4]
|
||||
emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) {
|
||||
// cmp rd, #imm
|
||||
emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF));
|
||||
}
|
||||
|
||||
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// cmp rd, rn
|
||||
emit_al(as, 0x1500000 | (rd << 16) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn) {
|
||||
asm_arm_cmp_reg_reg(as, rd, rn); // cmp rd, rn
|
||||
emit(as, asm_arm_op_mov_imm(REG_RET, 1) | ARM_CC_LT); // movlt REG_RET, #1
|
||||
emit(as, asm_arm_op_mov_imm(REG_RET, 0) | ARM_CC_GE); // movge REG_RET, #0
|
||||
}
|
||||
|
||||
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// add rd, rn, rm
|
||||
emit_al(as, asm_arm_op_add_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) {
|
||||
// add rd, sp, #local_num*4
|
||||
emit_al(as, asm_arm_op_add_imm(rd, REG_SP, local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
int dest = as->label_offsets[label];
|
||||
int rel = dest - as->code_offset;
|
||||
rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction
|
||||
rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted
|
||||
|
||||
if (SIGNED_FIT24(rel)) {
|
||||
emit(as, cond | 0xa000000 | (rel & 0xffffff));
|
||||
} else {
|
||||
printf("asm_arm_bcc: branch does not fit in 24 bits\n");
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_b_label(asm_arm_t *as, uint label) {
|
||||
asm_arm_bcc_label(as, ARM_CC_AL, label);
|
||||
}
|
||||
|
||||
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
|
||||
// If the table offset fits into the ldr instruction
|
||||
if(fun_id < (0x1000 / 4)) {
|
||||
emit_al(as, asm_arm_op_mov_reg(REG_LR, REG_PC)); // mov lr, pc
|
||||
emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4]
|
||||
return;
|
||||
}
|
||||
|
||||
emit_al(as, 0x59f0004 | (reg_temp << 12)); // ldr rd, [pc, #4]
|
||||
// Set lr after fun_ptr
|
||||
emit_al(as, asm_arm_op_add_imm(REG_LR, REG_PC, 4)); // add lr, pc, #4
|
||||
emit_al(as, asm_arm_op_mov_reg(REG_PC, reg_temp)); // mov pc, reg_temp
|
||||
emit(as, (uint) fun_ptr);
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_ARM
|
||||
104
py/asmarm.h
Normal file
104
py/asmarm.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Fabian Vogt
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define ASM_ARM_PASS_COMPUTE (1)
|
||||
#define ASM_ARM_PASS_EMIT (2)
|
||||
|
||||
#define REG_R0 (0)
|
||||
#define REG_R1 (1)
|
||||
#define REG_R2 (2)
|
||||
#define REG_R3 (3)
|
||||
#define REG_R4 (4)
|
||||
#define REG_R5 (5)
|
||||
#define REG_R6 (6)
|
||||
#define REG_R7 (7)
|
||||
#define REG_R8 (8)
|
||||
#define REG_R9 (9)
|
||||
#define REG_R10 (10)
|
||||
#define REG_R11 (11)
|
||||
#define REG_R12 (12)
|
||||
#define REG_R13 (13)
|
||||
#define REG_R14 (14)
|
||||
#define REG_R15 (15)
|
||||
#define REG_SP (REG_R13)
|
||||
#define REG_LR (REG_R14)
|
||||
#define REG_PC (REG_R15)
|
||||
|
||||
#define REG_RET REG_R0
|
||||
#define REG_ARG_1 REG_R0
|
||||
#define REG_ARG_2 REG_R1
|
||||
#define REG_ARG_3 REG_R2
|
||||
#define REG_ARG_4 REG_R3
|
||||
|
||||
#define ARM_CC_EQ (0x0 << 28)
|
||||
#define ARM_CC_NE (0x1 << 28)
|
||||
#define ARM_CC_CS (0x2 << 28)
|
||||
#define ARM_CC_CC (0x3 << 28)
|
||||
#define ARM_CC_MI (0x4 << 28)
|
||||
#define ARM_CC_PL (0x5 << 28)
|
||||
#define ARM_CC_VS (0x6 << 28)
|
||||
#define ARM_CC_VC (0x7 << 28)
|
||||
#define ARM_CC_HI (0x8 << 28)
|
||||
#define ARM_CC_LS (0x9 << 28)
|
||||
#define ARM_CC_GE (0xa << 28)
|
||||
#define ARM_CC_LT (0xb << 28)
|
||||
#define ARM_CC_GT (0xc << 28)
|
||||
#define ARM_CC_LE (0xd << 28)
|
||||
#define ARM_CC_AL (0xe << 28)
|
||||
|
||||
typedef struct _asm_arm_t asm_arm_t;
|
||||
|
||||
asm_arm_t *asm_arm_new(uint max_num_labels);
|
||||
void asm_arm_free(asm_arm_t *as, bool free_code);
|
||||
void asm_arm_start_pass(asm_arm_t *as, uint pass);
|
||||
void asm_arm_end_pass(asm_arm_t *as);
|
||||
uint asm_arm_get_code_size(asm_arm_t *as);
|
||||
void *asm_arm_get_code(asm_arm_t *as);
|
||||
|
||||
void asm_arm_entry(asm_arm_t *as, int num_locals);
|
||||
void asm_arm_exit(asm_arm_t *as);
|
||||
void asm_arm_label_assign(asm_arm_t *as, uint label);
|
||||
|
||||
void asm_arm_align(asm_arm_t* as, uint align);
|
||||
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val);
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as);
|
||||
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src);
|
||||
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm);
|
||||
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd);
|
||||
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num);
|
||||
|
||||
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm);
|
||||
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);
|
||||
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
|
||||
void asm_arm_b_label(asm_arm_t *as, uint label);
|
||||
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
|
||||
|
||||
128
py/asmthumb.c
128
py/asmthumb.c
@@ -1,9 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmthumb.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
@@ -16,11 +42,11 @@
|
||||
#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)
|
||||
|
||||
struct _asm_thumb_t {
|
||||
int pass;
|
||||
uint pass;
|
||||
uint code_offset;
|
||||
uint code_size;
|
||||
byte *code_base;
|
||||
byte dummy_data[8];
|
||||
byte dummy_data[4];
|
||||
|
||||
uint max_num_labels;
|
||||
int *label_offsets;
|
||||
@@ -32,14 +58,9 @@ struct _asm_thumb_t {
|
||||
asm_thumb_t *asm_thumb_new(uint max_num_labels) {
|
||||
asm_thumb_t *as;
|
||||
|
||||
as = m_new(asm_thumb_t, 1);
|
||||
as->pass = 0;
|
||||
as->code_offset = 0;
|
||||
as->code_size = 0;
|
||||
as->code_base = NULL;
|
||||
as = m_new0(asm_thumb_t, 1);
|
||||
as->max_num_labels = max_num_labels;
|
||||
as->label_offsets = m_new(int, max_num_labels);
|
||||
as->num_locals = 0;
|
||||
|
||||
return as;
|
||||
}
|
||||
@@ -63,16 +84,16 @@ void asm_thumb_free(asm_thumb_t *as, bool free_code) {
|
||||
m_del_obj(asm_thumb_t, as);
|
||||
}
|
||||
|
||||
void asm_thumb_start_pass(asm_thumb_t *as, int pass) {
|
||||
void asm_thumb_start_pass(asm_thumb_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_THUMB_PASS_2) {
|
||||
if (pass == ASM_THUMB_PASS_COMPUTE) {
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
if (as->pass == ASM_THUMB_PASS_2) {
|
||||
if (as->pass == ASM_THUMB_PASS_COMPUTE) {
|
||||
// calculate size of code in bytes
|
||||
as->code_size = as->code_offset;
|
||||
as->code_base = m_new(byte, as->code_size);
|
||||
@@ -92,9 +113,10 @@ void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit bytes
|
||||
// if as->pass < ASM_THUMB_PASS_EMIT, then this function only returns a buffer of 4 bytes length
|
||||
STATIC byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int num_bytes_to_write) {
|
||||
//printf("emit %d\n", num_bytes_to_write);
|
||||
if (as->pass < ASM_THUMB_PASS_3) {
|
||||
if (as->pass < ASM_THUMB_PASS_EMIT) {
|
||||
as->code_offset += num_bytes_to_write;
|
||||
return as->dummy_data;
|
||||
} else {
|
||||
@@ -110,8 +132,7 @@ uint asm_thumb_get_code_size(asm_thumb_t *as) {
|
||||
}
|
||||
|
||||
void *asm_thumb_get_code(asm_thumb_t *as) {
|
||||
// need to set low bit to indicate that it's thumb code
|
||||
return (void *)(((machine_uint_t)as->code_base) | 1);
|
||||
return as->code_base;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,15 +166,29 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) {
|
||||
#define OP_ADD_SP(num_words) (0xb000 | (num_words))
|
||||
#define OP_SUB_SP(num_words) (0xb080 | (num_words))
|
||||
|
||||
// locals:
|
||||
// - stored on the stack in ascending order
|
||||
// - numbered 0 through as->num_locals-1
|
||||
// - SP points to first local
|
||||
//
|
||||
// | SP
|
||||
// v
|
||||
// l0 l1 l2 ... l(n-1)
|
||||
// ^ ^
|
||||
// | low address | high address in RAM
|
||||
|
||||
void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
|
||||
// work out what to push and how many extra space to reserve on stack
|
||||
// work out what to push and how many extra spaces to reserve on stack
|
||||
// so that we have enough for all locals and it's aligned an 8-byte boundary
|
||||
// we push extra regs (r1, r2, r3) to help do the stack adjustment
|
||||
// we probably should just always subtract from sp, since this would be more efficient
|
||||
// for push rlist, lowest numbered register at the lowest address
|
||||
uint reglist;
|
||||
uint stack_adjust;
|
||||
if (num_locals < 0) {
|
||||
num_locals = 0;
|
||||
}
|
||||
// don't ppop r0 because it's used for return value
|
||||
// don't pop r0 because it's used for return value
|
||||
switch (num_locals) {
|
||||
case 0:
|
||||
reglist = 0xf2;
|
||||
@@ -198,12 +233,12 @@ void asm_thumb_exit(asm_thumb_t *as) {
|
||||
|
||||
void asm_thumb_label_assign(asm_thumb_t *as, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
if (as->pass == ASM_THUMB_PASS_2) {
|
||||
if (as->pass < ASM_THUMB_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(as->label_offsets[label] == -1);
|
||||
as->label_offsets[label] = as->code_offset;
|
||||
} else if (as->pass == ASM_THUMB_PASS_3) {
|
||||
// ensure label offset has not changed from PASS_2 to PASS_3
|
||||
} else {
|
||||
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
|
||||
//printf("l%d: (at %d=%ld)\n", label, as->label_offsets[label], as->code_offset);
|
||||
assert(as->label_offsets[label] == as->code_offset);
|
||||
}
|
||||
@@ -216,10 +251,13 @@ void asm_thumb_align(asm_thumb_t* as, uint align) {
|
||||
|
||||
void asm_thumb_data(asm_thumb_t* as, uint bytesize, uint val) {
|
||||
byte *c = asm_thumb_get_cur_to_write_bytes(as, bytesize);
|
||||
// little endian
|
||||
for (uint i = 0; i < bytesize; i++) {
|
||||
*c++ = val;
|
||||
val >>= 8;
|
||||
// only write to the buffer in the emit pass (otherwise we overflow dummy_data)
|
||||
if (as->pass == ASM_THUMB_PASS_EMIT) {
|
||||
// little endian
|
||||
for (uint i = 0; i < bytesize; i++) {
|
||||
*c++ = val;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +377,7 @@ void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label) {
|
||||
}
|
||||
}
|
||||
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32) {
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
|
||||
// movw, movt does it in 8 bytes
|
||||
// ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw
|
||||
|
||||
@@ -357,20 +395,35 @@ void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) {
|
||||
}
|
||||
}
|
||||
|
||||
// i32 is stored as a full word in the code, and aligned to machine-word boundary
|
||||
// TODO this is very inefficient, improve it!
|
||||
void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) {
|
||||
// align on machine-word + 2
|
||||
if ((as->code_offset & 3) == 0) {
|
||||
asm_thumb_op16(as, ASM_THUMB_OP_NOP);
|
||||
}
|
||||
// jump over the i32 value (instruction prefect adds 4 to PC)
|
||||
asm_thumb_op16(as, OP_B_N(0));
|
||||
// store i32 on machine-word aligned boundary
|
||||
asm_thumb_data(as, 4, i32);
|
||||
// do the actual load of the i32 value
|
||||
asm_thumb_mov_reg_i32_optimised(as, reg_dest, i32);
|
||||
}
|
||||
|
||||
#define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
|
||||
#define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
|
||||
|
||||
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) {
|
||||
assert(rlo_src < REG_R8);
|
||||
int word_offset = as->num_locals - local_num - 1;
|
||||
assert(as->pass < ASM_THUMB_PASS_3 || word_offset >= 0);
|
||||
int word_offset = local_num;
|
||||
assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0);
|
||||
asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset));
|
||||
}
|
||||
|
||||
void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) {
|
||||
assert(rlo_dest < REG_R8);
|
||||
int word_offset = as->num_locals - local_num - 1;
|
||||
assert(as->pass < ASM_THUMB_PASS_3 || word_offset >= 0);
|
||||
int word_offset = local_num;
|
||||
assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0);
|
||||
asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset));
|
||||
}
|
||||
|
||||
@@ -378,8 +431,8 @@ void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) {
|
||||
|
||||
void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) {
|
||||
assert(rlo_dest < REG_R8);
|
||||
int word_offset = as->num_locals - local_num - 1;
|
||||
assert(as->pass < ASM_THUMB_PASS_3 || word_offset >= 0);
|
||||
int word_offset = local_num;
|
||||
assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0);
|
||||
asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset));
|
||||
}
|
||||
|
||||
@@ -442,17 +495,14 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
|
||||
asm_thumb_op16(as, 0x4780 | (REG_R9 << 3)); // blx reg
|
||||
*/
|
||||
|
||||
if (0) {
|
||||
// load ptr to function into register using immediate, then branch
|
||||
// not relocatable
|
||||
asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr);
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
} else if (1) {
|
||||
if (fun_id < 32) {
|
||||
// load ptr to function from table, indexed by fun_id (must be in range 0-31); 4 bytes
|
||||
asm_thumb_op16(as, OP_FORMAT_9_10(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, reg_temp, REG_R7, fun_id));
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
} else {
|
||||
// use SVC
|
||||
asm_thumb_op16(as, OP_SVC(fun_id));
|
||||
// load ptr to function into register using immediate; 6 bytes
|
||||
asm_thumb_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr);
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
#define ASM_THUMB_PASS_1 (1)
|
||||
#define ASM_THUMB_PASS_2 (2)
|
||||
#define ASM_THUMB_PASS_3 (3)
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define ASM_THUMB_PASS_COMPUTE (1)
|
||||
#define ASM_THUMB_PASS_EMIT (2)
|
||||
|
||||
#define REG_R0 (0)
|
||||
#define REG_R1 (1)
|
||||
@@ -45,7 +70,7 @@ typedef struct _asm_thumb_t asm_thumb_t;
|
||||
|
||||
asm_thumb_t *asm_thumb_new(uint max_num_labels);
|
||||
void asm_thumb_free(asm_thumb_t *as, bool free_code);
|
||||
void asm_thumb_start_pass(asm_thumb_t *as, int pass);
|
||||
void asm_thumb_start_pass(asm_thumb_t *as, uint pass);
|
||||
void asm_thumb_end_pass(asm_thumb_t *as);
|
||||
uint asm_thumb_get_code_size(asm_thumb_t *as);
|
||||
void *asm_thumb_get_code(asm_thumb_t *as);
|
||||
@@ -160,8 +185,9 @@ void asm_thumb_ite_ge(asm_thumb_t *as);
|
||||
void asm_thumb_b_n(asm_thumb_t *as, uint label);
|
||||
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
|
||||
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32); // convenience
|
||||
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience
|
||||
void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience
|
||||
void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience
|
||||
|
||||
60
py/asmx64.c
60
py/asmx64.c
@@ -1,10 +1,36 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_X64
|
||||
@@ -86,7 +112,7 @@
|
||||
#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
|
||||
|
||||
struct _asm_x64_t {
|
||||
int pass;
|
||||
uint pass;
|
||||
uint code_offset;
|
||||
uint code_size;
|
||||
byte *code_base;
|
||||
@@ -112,14 +138,9 @@ void *alloc_mem(uint req_size, uint *alloc_size, bool is_exec) {
|
||||
asm_x64_t *asm_x64_new(uint max_num_labels) {
|
||||
asm_x64_t *as;
|
||||
|
||||
as = m_new(asm_x64_t, 1);
|
||||
as->pass = 0;
|
||||
as->code_offset = 0;
|
||||
as->code_size = 0;
|
||||
as->code_base = NULL;
|
||||
as = m_new0(asm_x64_t, 1);
|
||||
as->max_num_labels = max_num_labels;
|
||||
as->label_offsets = m_new(int, max_num_labels);
|
||||
as->num_locals = 0;
|
||||
|
||||
return as;
|
||||
}
|
||||
@@ -144,17 +165,17 @@ void asm_x64_free(asm_x64_t *as, bool free_code) {
|
||||
m_del_obj(asm_x64_t, as);
|
||||
}
|
||||
|
||||
void asm_x64_start_pass(asm_x64_t *as, int pass) {
|
||||
void asm_x64_start_pass(asm_x64_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_X64_PASS_2) {
|
||||
if (pass == ASM_X64_PASS_COMPUTE) {
|
||||
// reset all labels
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_x64_end_pass(asm_x64_t *as) {
|
||||
if (as->pass == ASM_X64_PASS_2) {
|
||||
if (as->pass == ASM_X64_PASS_COMPUTE) {
|
||||
// calculate size of code in bytes
|
||||
as->code_size = as->code_offset;
|
||||
//as->code_base = m_new(byte, as->code_size); need to allocale executable memory
|
||||
@@ -178,7 +199,7 @@ void asm_x64_end_pass(asm_x64_t *as) {
|
||||
// all functions must go through this one to emit bytes
|
||||
STATIC byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int num_bytes_to_write) {
|
||||
//printf("emit %d\n", num_bytes_to_write);
|
||||
if (as->pass < ASM_X64_PASS_3) {
|
||||
if (as->pass < ASM_X64_PASS_EMIT) {
|
||||
as->code_offset += num_bytes_to_write;
|
||||
return as->dummy_data;
|
||||
} else {
|
||||
@@ -341,6 +362,15 @@ void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r
|
||||
}
|
||||
}
|
||||
|
||||
// src_i64 is stored as a full word in the code, and aligned to machine-word boundary
|
||||
void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64) {
|
||||
// mov instruction uses 2 bytes for the instruction, before the i64
|
||||
while (((as->code_offset + 2) & (WORD_SIZE - 1)) != 0) {
|
||||
asm_x64_nop(as);
|
||||
}
|
||||
asm_x64_mov_i64_to_r64(as, src_i64, dest_r64);
|
||||
}
|
||||
|
||||
void asm_x64_mov_i32_to_disp(asm_x64_t *as, int src_i32, int dest_r32, int dest_disp)
|
||||
{
|
||||
assert(0);
|
||||
@@ -461,12 +491,12 @@ void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) {
|
||||
|
||||
void asm_x64_label_assign(asm_x64_t *as, int label) {
|
||||
assert(label < as->max_num_labels);
|
||||
if (as->pass == ASM_X64_PASS_2) {
|
||||
if (as->pass < ASM_X64_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(as->label_offsets[label] == -1);
|
||||
as->label_offsets[label] = as->code_offset;
|
||||
} else if (as->pass == ASM_X64_PASS_3) {
|
||||
// ensure label offset has not changed from PASS_2 to PASS_3
|
||||
} else {
|
||||
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
|
||||
//printf("l%d: (at %d=%ld)\n", label, as->label_offsets[label], as->code_offset);
|
||||
assert(as->label_offsets[label] == as->code_offset);
|
||||
}
|
||||
|
||||
34
py/asmx64.h
34
py/asmx64.h
@@ -1,6 +1,31 @@
|
||||
#define ASM_X64_PASS_1 (1)
|
||||
#define ASM_X64_PASS_2 (2)
|
||||
#define ASM_X64_PASS_3 (3)
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define ASM_X64_PASS_COMPUTE (1)
|
||||
#define ASM_X64_PASS_EMIT (2)
|
||||
|
||||
#define REG_RAX (0)
|
||||
#define REG_RCX (1)
|
||||
@@ -28,7 +53,7 @@ typedef struct _asm_x64_t asm_x64_t;
|
||||
|
||||
asm_x64_t* asm_x64_new(uint max_num_labels);
|
||||
void asm_x64_free(asm_x64_t* as, bool free_code);
|
||||
void asm_x64_start_pass(asm_x64_t *as, int pass);
|
||||
void asm_x64_start_pass(asm_x64_t *as, uint pass);
|
||||
void asm_x64_end_pass(asm_x64_t *as);
|
||||
uint asm_x64_get_code_size(asm_x64_t* as);
|
||||
void* asm_x64_get_code(asm_x64_t* as);
|
||||
@@ -45,6 +70,7 @@ void asm_x64_mov_i32_to_r64(asm_x64_t* as, int src_i32, int dest_r64);
|
||||
void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_i32_to_disp(asm_x64_t* as, int src_i32, int dest_r32, int dest_disp);
|
||||
void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_xor_r64_to_r64(asm_x64_t *as, int src_r64, int dest_r64);
|
||||
void asm_x64_add_r64_to_r64(asm_x64_t* as, int src_r64, int dest_r64);
|
||||
void asm_x64_add_i32_to_r32(asm_x64_t* as, int src_i32, int dest_r32);
|
||||
|
||||
53
py/bc.h
53
py/bc.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Exception stack entry
|
||||
typedef struct _mp_exc_stack {
|
||||
const byte *handler;
|
||||
@@ -10,12 +36,25 @@ typedef struct _mp_exc_stack {
|
||||
byte opcode;
|
||||
} mp_exc_stack_t;
|
||||
|
||||
mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret);
|
||||
mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out, volatile mp_obj_t inject_exc);
|
||||
void mp_byte_code_print(const byte *code, int len);
|
||||
void mp_byte_code_print2(const byte *code, int len);
|
||||
typedef struct _mp_code_state {
|
||||
const byte *code_info;
|
||||
const byte *ip;
|
||||
mp_obj_t *sp;
|
||||
// bit 0 is saved currently_in_except_block value
|
||||
mp_exc_stack_t *exc_sp;
|
||||
uint n_state;
|
||||
// Variable-length
|
||||
mp_obj_t state[0];
|
||||
// Variable-length, never accessed by name, only as (void*)(state + n_state)
|
||||
//mp_exc_stack_t exc_state[0];
|
||||
} mp_code_state;
|
||||
|
||||
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
|
||||
void mp_bytecode_print(const void *descr, const byte *code, int len);
|
||||
void mp_bytecode_print2(const byte *code, int len);
|
||||
|
||||
// Helper macros to access pointer with least significant bit holding a flag
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((machine_uint_t)(x) & ~((machine_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((machine_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((machine_uint_t)(ptr) | tag))
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((mp_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | tag))
|
||||
|
||||
26
py/bc0.h
26
py/bc0.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Micro Python byte-codes.
|
||||
// The comment at the end of the line (if it exists) tells the arguments to the byte-code.
|
||||
|
||||
|
||||
148
py/binary.c
148
py/binary.c
@@ -1,15 +1,47 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "binary.h"
|
||||
|
||||
// Helpers to work with binary-encoded data
|
||||
|
||||
#ifndef alignof
|
||||
#define alignof(type) offsetof(struct { char c; type t; }, t)
|
||||
#endif
|
||||
|
||||
int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
int size = 0;
|
||||
int align = 1;
|
||||
@@ -41,16 +73,20 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
case 'b': case 'B':
|
||||
align = size = 1; break;
|
||||
case 'h': case 'H':
|
||||
align = size = sizeof(short); break;
|
||||
align = alignof(short);
|
||||
size = sizeof(short); break;
|
||||
case 'i': case 'I':
|
||||
align = size = sizeof(int); break;
|
||||
align = alignof(int);
|
||||
size = sizeof(int); break;
|
||||
case 'l': case 'L':
|
||||
align = size = sizeof(long); break;
|
||||
align = alignof(long);
|
||||
size = sizeof(long); break;
|
||||
case 'q': case 'Q':
|
||||
// TODO: This is for x86
|
||||
align = sizeof(int); size = sizeof(long long); break;
|
||||
case 'P': case 'O':
|
||||
align = size = sizeof(void*); break;
|
||||
align = alignof(long long);
|
||||
size = sizeof(long long); break;
|
||||
case 'P': case 'O': case 'S':
|
||||
align = alignof(void*);
|
||||
size = sizeof(void*); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +97,7 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
}
|
||||
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
machine_int_t val = 0;
|
||||
mp_int_t val = 0;
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
val = ((int8_t*)p)[index];
|
||||
@@ -88,7 +124,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
// TODO: Explode API more to cover signedness
|
||||
return mp_obj_new_int_from_ll(((long long*)p)[index]);
|
||||
#endif
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
return mp_obj_new_float(((float*)p)[index]);
|
||||
case 'd':
|
||||
@@ -98,6 +134,28 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
}
|
||||
|
||||
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p) {
|
||||
int delta;
|
||||
if (!big_endian) {
|
||||
delta = -1;
|
||||
p += size - 1;
|
||||
} else {
|
||||
delta = 1;
|
||||
}
|
||||
|
||||
mp_int_t val = 0;
|
||||
if (is_signed && *p & 0x80) {
|
||||
val = -1;
|
||||
}
|
||||
for (uint i = 0; i < size; i++) {
|
||||
val <<= 8;
|
||||
val |= *p;
|
||||
p += delta;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#define is_signed(typecode) (typecode > 'Z')
|
||||
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
byte *p = *ptr;
|
||||
@@ -106,35 +164,21 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
int delta;
|
||||
if (struct_type == '<') {
|
||||
delta = -1;
|
||||
p += size - 1;
|
||||
} else {
|
||||
delta = 1;
|
||||
}
|
||||
mp_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
|
||||
|
||||
machine_int_t val = 0;
|
||||
if (is_signed(val_type) && *p & 0x80) {
|
||||
val = -1;
|
||||
}
|
||||
for (uint i = 0; i < size; i++) {
|
||||
val <<= 8;
|
||||
val |= *p;
|
||||
p += delta;
|
||||
}
|
||||
|
||||
*ptr += size;
|
||||
if (val_type == 'O') {
|
||||
return (mp_obj_t)val;
|
||||
} else if (val_type == 'S') {
|
||||
return mp_obj_new_str((char*)val, strlen((char*)val), false);
|
||||
} else if (is_signed(val_type)) {
|
||||
return mp_obj_new_int(val);
|
||||
} else {
|
||||
@@ -142,6 +186,23 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr) {
|
||||
int in_delta, out_delta;
|
||||
if (big_endian) {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
val_ptr += val_sz - 1;
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *val_ptr;
|
||||
p += out_delta;
|
||||
val_ptr += in_delta;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
|
||||
byte *p = *ptr;
|
||||
uint align;
|
||||
@@ -149,18 +210,19 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
#if MP_ENDIANNESS_BIG
|
||||
#error Not implemented
|
||||
#endif
|
||||
machine_int_t val;
|
||||
mp_int_t val;
|
||||
byte *in = (byte*)&val;
|
||||
switch (val_type) {
|
||||
case 'O':
|
||||
@@ -170,28 +232,12 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
val = mp_obj_get_int(val_in);
|
||||
}
|
||||
|
||||
int in_delta, out_delta;
|
||||
uint val_sz = MIN(size, sizeof(val));
|
||||
if (struct_type == '>') {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
in += val_sz - 1;
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *in;
|
||||
p += out_delta;
|
||||
in += in_delta;
|
||||
}
|
||||
|
||||
*ptr += size;
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
|
||||
switch (typecode) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
((float*)p)[index] = mp_obj_float_get(val_in);
|
||||
break;
|
||||
@@ -204,7 +250,7 @@ void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in)
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val) {
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
((int8_t*)p)[index] = val;
|
||||
@@ -234,7 +280,7 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine
|
||||
((long long*)p)[index] = val;
|
||||
break;
|
||||
#endif
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
((float*)p)[index] = val;
|
||||
break;
|
||||
|
||||
30
py/binary.h
30
py/binary.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Use special typecode to differentiate repr() of bytearray vs array.array('B')
|
||||
// (underlyingly they're same).
|
||||
#define BYTEARRAY_TYPECODE 0
|
||||
@@ -5,6 +31,8 @@
|
||||
int mp_binary_get_size(char struct_type, char val_type, uint *palign);
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index);
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val);
|
||||
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
|
||||
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p);
|
||||
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr);
|
||||
|
||||
242
py/builtin.c
242
py/builtin.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -10,8 +36,10 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "stream.h"
|
||||
#include "pfenv.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
@@ -71,14 +99,14 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
|
||||
|
||||
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
if (val < 0) {
|
||||
val = -val;
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_float)) {
|
||||
mp_float_t value = mp_obj_float_get(o_in);
|
||||
// TODO check for NaN etc
|
||||
@@ -87,10 +115,12 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
} else {
|
||||
return o_in;
|
||||
}
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_complex)) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_complex_get(o_in, &real, &imag);
|
||||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag));
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
assert(0);
|
||||
@@ -128,7 +158,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {
|
||||
mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };
|
||||
return mp_obj_str_format(ARRAY_SIZE(args), args);
|
||||
return mp_obj_str_format(MP_ARRAY_SIZE(args), args);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
|
||||
@@ -144,13 +174,40 @@ STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
|
||||
int ord = mp_obj_get_int(o_in);
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
mp_uint_t c = mp_obj_get_int(o_in);
|
||||
char str[4];
|
||||
int len = 0;
|
||||
if (c < 0x80) {
|
||||
*str = c; len = 1;
|
||||
} else if (c < 0x800) {
|
||||
str[0] = (c >> 6) | 0xC0;
|
||||
str[1] = (c & 0x3F) | 0x80;
|
||||
len = 2;
|
||||
} else if (c < 0x10000) {
|
||||
str[0] = (c >> 12) | 0xE0;
|
||||
str[1] = ((c >> 6) & 0x3F) | 0x80;
|
||||
str[2] = (c & 0x3F) | 0x80;
|
||||
len = 3;
|
||||
} else if (c < 0x110000) {
|
||||
str[0] = (c >> 18) | 0xF0;
|
||||
str[1] = ((c >> 12) & 0x3F) | 0x80;
|
||||
str[2] = ((c >> 6) & 0x3F) | 0x80;
|
||||
str[3] = (c & 0x3F) | 0x80;
|
||||
len = 4;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
|
||||
}
|
||||
return mp_obj_new_str(str, len, true);
|
||||
#else
|
||||
mp_int_t ord = mp_obj_get_int(o_in);
|
||||
if (0 <= ord && ord <= 0x10ffff) {
|
||||
byte str[1] = {ord};
|
||||
char str[1] = {ord};
|
||||
return mp_obj_new_str(str, 1, true);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);
|
||||
@@ -195,8 +252,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
|
||||
mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
||||
mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
|
||||
mp_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
||||
mp_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
|
||||
mp_obj_t args[2];
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
|
||||
@@ -227,74 +284,50 @@ STATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_len(mp_obj_t o_in) {
|
||||
mp_obj_t len = mp_obj_len_maybe(o_in);
|
||||
if (len == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
|
||||
} else {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_builtin_len);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t mp_builtin_min_max(uint n_args, const mp_obj_t *args, mp_map_t *kwargs, int op) {
|
||||
mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP);
|
||||
mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value;
|
||||
if (n_args == 1) {
|
||||
// given an iterable
|
||||
mp_obj_t iterable = mp_getiter(args[0]);
|
||||
mp_obj_t max_obj = NULL;
|
||||
mp_obj_t best_key = MP_OBJ_NULL;
|
||||
mp_obj_t best_obj = MP_OBJ_NULL;
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if (max_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, max_obj, item) == mp_const_true)) {
|
||||
max_obj = item;
|
||||
mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item);
|
||||
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
|
||||
best_key = key;
|
||||
best_obj = item;
|
||||
}
|
||||
}
|
||||
if (max_obj == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence"));
|
||||
if (best_obj == MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "arg is an empty sequence"));
|
||||
}
|
||||
return max_obj;
|
||||
return best_obj;
|
||||
} else {
|
||||
// given many args
|
||||
mp_obj_t max_obj = args[0];
|
||||
for (int i = 1; i < n_args; i++) {
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i]) == mp_const_true) {
|
||||
max_obj = args[i];
|
||||
mp_obj_t best_key = MP_OBJ_NULL;
|
||||
mp_obj_t best_obj = MP_OBJ_NULL;
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]);
|
||||
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
|
||||
best_key = key;
|
||||
best_obj = args[i];
|
||||
}
|
||||
}
|
||||
return max_obj;
|
||||
return best_obj;
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_max_obj, 1, mp_builtin_max);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 1) {
|
||||
// given an iterable
|
||||
mp_obj_t iterable = mp_getiter(args[0]);
|
||||
mp_obj_t min_obj = NULL;
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if (min_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, item, min_obj) == mp_const_true)) {
|
||||
min_obj = item;
|
||||
}
|
||||
}
|
||||
if (min_obj == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence"));
|
||||
}
|
||||
return min_obj;
|
||||
} else {
|
||||
// given many args
|
||||
mp_obj_t min_obj = args[0];
|
||||
for (int i = 1; i < n_args; i++) {
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj) == mp_const_true) {
|
||||
min_obj = args[i];
|
||||
}
|
||||
}
|
||||
return min_obj;
|
||||
}
|
||||
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max);
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
|
||||
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
|
||||
mp_obj_t ret = mp_iternext_allow_raise(o);
|
||||
@@ -316,13 +349,32 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
|
||||
STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
|
||||
uint len;
|
||||
const char *str = mp_obj_str_get_data(o_in, &len);
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
mp_uint_t charlen = unichar_charlen(str, len);
|
||||
if (charlen == 1) {
|
||||
if (MP_OBJ_IS_STR(o_in) && UTF8_IS_NONASCII(*str)) {
|
||||
mp_int_t ord = *str++ & 0x7F;
|
||||
for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) {
|
||||
ord &= ~mask;
|
||||
}
|
||||
while (UTF8_IS_CONT(*str)) {
|
||||
ord = (ord << 6) | (*str++ & 0x3F);
|
||||
}
|
||||
return mp_obj_new_int(ord);
|
||||
} else {
|
||||
return mp_obj_new_int(((const byte*)str)[0]);
|
||||
}
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", charlen));
|
||||
}
|
||||
#else
|
||||
if (len == 1) {
|
||||
// don't sign extend when converting to ord
|
||||
// TODO unicode
|
||||
return mp_obj_new_int(((const byte*)str)[0]);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);
|
||||
@@ -350,13 +402,36 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw
|
||||
if (end_elem != NULL && end_elem->value != mp_const_none) {
|
||||
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_obj_t stream_obj = &mp_sys_stdout_obj;
|
||||
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
|
||||
if (file_elem != NULL && file_elem->value != mp_const_none) {
|
||||
stream_obj = file_elem->value;
|
||||
}
|
||||
|
||||
pfenv_t pfenv;
|
||||
pfenv.data = stream_obj;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
|
||||
#endif
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
if (i > 0) {
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, sep_data, sep_len);
|
||||
#else
|
||||
printf("%.*s", sep_len, sep_data);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR);
|
||||
#else
|
||||
mp_obj_print(args[i], PRINT_STR);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, end_data, end_len);
|
||||
#else
|
||||
printf("%.*s", end_len, end_data);
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
@@ -365,7 +440,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print);
|
||||
STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
|
||||
vstr_t *vstr = vstr_new();
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR);
|
||||
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
|
||||
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
@@ -404,7 +479,21 @@ STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *k
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_id(mp_obj_t o_in) {
|
||||
return mp_obj_new_int((machine_int_t)o_in);
|
||||
mp_int_t id = (mp_int_t)o_in;
|
||||
if (!MP_OBJ_IS_OBJ(o_in)) {
|
||||
return mp_obj_new_int(id);
|
||||
} else if (id >= 0) {
|
||||
// Many OSes and CPUs have affinity for putting "user" memories
|
||||
// into low half of address space, and "system" into upper half.
|
||||
// We're going to take advantage of that and return small int
|
||||
// (signed) for such "user" addresses.
|
||||
return MP_OBJ_NEW_SMALL_INT(id);
|
||||
} else {
|
||||
// If that didn't work, well, let's return long int, just as
|
||||
// a (big) positve value, so it will never clash with the range
|
||||
// of small int returned in previous case.
|
||||
return mp_obj_new_int_from_uint((mp_uint_t)id);
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_builtin_id);
|
||||
@@ -426,16 +515,37 @@ STATIC inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t d
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_getattr(uint n_args, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_QSTR(args[1]));
|
||||
mp_obj_t attr = args[1];
|
||||
if (MP_OBJ_IS_TYPE(attr, &mp_type_str)) {
|
||||
attr = mp_obj_str_intern(attr);
|
||||
} else if (!MP_OBJ_IS_QSTR(attr)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "string required"));
|
||||
}
|
||||
mp_obj_t defval = MP_OBJ_NULL;
|
||||
if (n_args > 2) {
|
||||
defval = args[2];
|
||||
}
|
||||
return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(args[1]), defval);
|
||||
return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(attr), defval);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr);
|
||||
|
||||
// These two are defined in terms of MicroPython API functions right away
|
||||
STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
|
||||
assert(MP_OBJ_IS_QSTR(attr_in));
|
||||
|
||||
mp_obj_t dest[2];
|
||||
// TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr
|
||||
// explicitly says "This is implemented by calling getattr(object, name) and seeing
|
||||
// whether it raises an AttributeError or not.", so we should explicitly wrap this
|
||||
// in nlr_push and handle exception.
|
||||
mp_load_method_maybe(object_in, MP_OBJ_QSTR_VALUE(attr_in), dest);
|
||||
|
||||
return MP_BOOL(dest[0] != MP_OBJ_NULL);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);
|
||||
|
||||
// These are defined in terms of MicroPython API functions right away
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_globals_get);
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_locals_get);
|
||||
|
||||
39
py/builtin.h
39
py/builtin.h
@@ -1,4 +1,32 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_len(mp_obj_t o);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
|
||||
@@ -15,6 +43,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_eval_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_exec_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_getattr_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_globals_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hasattr_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hash_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hex_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_id_obj);
|
||||
@@ -51,3 +80,13 @@ extern const mp_obj_module_t mp_module_cmath;
|
||||
extern const mp_obj_module_t mp_module_micropython;
|
||||
extern const mp_obj_module_t mp_module_struct;
|
||||
extern const mp_obj_module_t mp_module_sys;
|
||||
extern const mp_obj_module_t mp_module_gc;
|
||||
|
||||
struct _dummy_t;
|
||||
extern struct _dummy_t mp_sys_stdin_obj;
|
||||
extern struct _dummy_t mp_sys_stdout_obj;
|
||||
extern struct _dummy_t mp_sys_stderr_obj;
|
||||
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
extern const mp_obj_module_t mp_module_zlibd;
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
@@ -28,7 +54,7 @@
|
||||
|
||||
#define PATH_SEP_CHAR '/'
|
||||
|
||||
mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
//printf("stat %s\n", vstr_str(path));
|
||||
mp_import_stat_t stat = mp_import_stat(vstr_str(path));
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
@@ -42,11 +68,11 @@ mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
// extract the list of paths
|
||||
uint path_num = 0;
|
||||
mp_obj_t *path_items;
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
|
||||
#endif
|
||||
|
||||
@@ -76,7 +102,7 @@ mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
}
|
||||
}
|
||||
|
||||
void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
|
||||
|
||||
@@ -94,6 +120,9 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// set the new context
|
||||
mp_locals_set(mp_obj_module_get_globals(module_obj));
|
||||
mp_globals_set(mp_obj_module_get_globals(module_obj));
|
||||
#if MICROPY_PY___FILE__
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, mp_obj_new_str(vstr_str(file), vstr_len(file), false));
|
||||
#endif
|
||||
|
||||
// parse the imported script
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
@@ -136,16 +165,6 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
mp_globals_set(old_globals);
|
||||
}
|
||||
|
||||
// TODO: Move to objdict?
|
||||
STATIC inline mp_obj_t mp_obj_dict_get(mp_obj_t dict_in, mp_obj_t key) {
|
||||
mp_obj_dict_t *dict = dict_in;
|
||||
mp_map_elem_t *elem = mp_map_lookup(&dict->map, key, MP_MAP_LOOKUP);
|
||||
if (elem == NULL) {
|
||||
return elem;
|
||||
}
|
||||
return elem->value;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
#if DEBUG_PRINT
|
||||
printf("__import__:\n");
|
||||
@@ -251,7 +270,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
DEBUG_printf("Module not yet loaded\n");
|
||||
|
||||
uint last = 0;
|
||||
VSTR_FIXED(path, MICROPY_PATH_MAX)
|
||||
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
|
||||
module_obj = MP_OBJ_NULL;
|
||||
mp_obj_t top_module_obj = MP_OBJ_NULL;
|
||||
mp_obj_t outer_module_obj = MP_OBJ_NULL;
|
||||
@@ -261,6 +280,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
// create a qstr for the module name up to this depth
|
||||
qstr mod_name = qstr_from_strn(mod_str, i);
|
||||
DEBUG_printf("Processing module: %s\n", qstr_str(mod_name));
|
||||
DEBUG_printf("Previous path: %s\n", vstr_str(&path));
|
||||
|
||||
// find the file corresponding to the module name
|
||||
mp_import_stat_t stat;
|
||||
@@ -273,6 +293,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
vstr_add_strn(&path, mod_str + last, i - last);
|
||||
stat = stat_dir_or_file(&path);
|
||||
}
|
||||
DEBUG_printf("Current path: %s\n", vstr_str(&path));
|
||||
|
||||
// fail if we couldn't find the file
|
||||
if (stat == MP_IMPORT_STAT_NO_EXIST) {
|
||||
@@ -287,7 +308,9 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
DEBUG_printf("%s is dir\n", vstr_str(&path));
|
||||
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str((byte*)vstr_str(&path), vstr_len(&path), false));
|
||||
// https://docs.python.org/3/reference/import.html
|
||||
// "Specifically, any module that contains a __path__ attribute is considered a package."
|
||||
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false));
|
||||
vstr_add_char(&path, PATH_SEP_CHAR);
|
||||
vstr_add_str(&path, "__init__.py");
|
||||
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
|
||||
@@ -295,10 +318,8 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
printf("Notice: %s is imported as namespace package\n", vstr_str(&path));
|
||||
} else {
|
||||
do_load(module_obj, &path);
|
||||
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
|
||||
}
|
||||
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
|
||||
// https://docs.python.org/3.3/reference/import.html
|
||||
// "Specifically, any module that contains a __path__ attribute is considered a package."
|
||||
} else { // MP_IMPORT_STAT_FILE
|
||||
do_load(module_obj, &path);
|
||||
// TODO: We cannot just break here, at the very least, we must execute
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -17,25 +43,33 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
// built-in types
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bool), (mp_obj_t)&mp_type_bool },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes), (mp_obj_t)&mp_type_bytes },
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray },
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#endif
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_complex), (mp_obj_t)&mp_type_complex },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dict), (mp_obj_t)&mp_type_dict },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enumerate), (mp_obj_t)&mp_type_enumerate },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_filter), (mp_obj_t)&mp_type_filter },
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_float), (mp_obj_t)&mp_type_float },
|
||||
#endif
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_frozenset), (mp_obj_t)&mp_type_frozenset },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_int), (mp_obj_t)&mp_type_int },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_list), (mp_obj_t)&mp_type_list },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_map), (mp_obj_t)&mp_type_map },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_object), (mp_obj_t)&mp_type_object },
|
||||
#if MICROPY_ENABLE_PROPERTY
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_range), (mp_obj_t)&mp_type_range },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reversed), (mp_obj_t)&mp_type_reversed },
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&mp_type_set },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_str), (mp_obj_t)&mp_type_str },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_super), (mp_obj_t)&mp_type_super },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_tuple), (mp_obj_t)&mp_type_tuple },
|
||||
@@ -61,6 +95,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_exec), (mp_obj_t)&mp_builtin_exec_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getattr), (mp_obj_t)&mp_builtin_getattr_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_globals), (mp_obj_t)&mp_builtin_globals_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hasattr), (mp_obj_t)&mp_builtin_hasattr_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hash), (mp_obj_t)&mp_builtin_hash_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hex), (mp_obj_t)&mp_builtin_hex_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_id), (mp_obj_t)&mp_builtin_id_obj },
|
||||
@@ -103,6 +138,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_StopIteration), (mp_obj_t)&mp_type_StopIteration },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SyntaxError), (mp_obj_t)&mp_type_SyntaxError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemError), (mp_obj_t)&mp_type_SystemError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemExit), (mp_obj_t)&mp_type_SystemExit },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_TypeError), (mp_obj_t)&mp_type_TypeError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ValueError), (mp_obj_t)&mp_type_ValueError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ZeroDivisionError), (mp_obj_t)&mp_type_ZeroDivisionError },
|
||||
@@ -110,7 +146,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
// TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation
|
||||
|
||||
// Extra builtins as defined by a port
|
||||
MICROPY_EXTRA_BUILTINS
|
||||
MICROPY_PORT_BUILTINS
|
||||
};
|
||||
|
||||
const mp_obj_dict_t mp_builtin_object_dict_obj = {
|
||||
@@ -118,8 +154,8 @@ const mp_obj_dict_t mp_builtin_object_dict_obj = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_builtin_object_table),
|
||||
.alloc = ARRAY_SIZE(mp_builtin_object_table),
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_object_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_object_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_object_table,
|
||||
},
|
||||
};
|
||||
@@ -128,29 +164,45 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___main__), (mp_obj_t)&mp_module___main__ },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array },
|
||||
#if MICROPY_ENABLE_MOD_IO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#if MICROPY_PY_IO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
|
||||
#endif
|
||||
#if MICROPY_PY_COLLECTIONS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__collections), (mp_obj_t)&mp_module_collections },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_STRUCT
|
||||
#if MICROPY_PY_STRUCT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_struct },
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#if MICROPY_PY_MATH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&mp_module_math },
|
||||
#if MICROPY_ENABLE_MOD_CMATH
|
||||
#endif
|
||||
#if MICROPY_PY_CMATH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_cmath), (mp_obj_t)&mp_module_cmath },
|
||||
#endif
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sys), (mp_obj_t)&mp_module_sys },
|
||||
#endif
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&mp_module_gc },
|
||||
#endif
|
||||
|
||||
// extmod modules
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
#if MICROPY_PY_ZLIBD
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
|
||||
#endif
|
||||
|
||||
// extra builtin modules as defined by a port
|
||||
MICROPY_EXTRA_BUILTIN_MODULES
|
||||
MICROPY_PORT_BUILTIN_MODULES
|
||||
};
|
||||
|
||||
const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
@@ -158,8 +210,8 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_builtin_module_table),
|
||||
.alloc = ARRAY_SIZE(mp_builtin_module_table),
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_module_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_module_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_table,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,2 +1,28 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern const mp_obj_dict_t mp_builtin_object_dict_obj;
|
||||
extern const mp_obj_dict_t mp_builtin_module_dict_obj;
|
||||
|
||||
489
py/compile.c
489
py/compile.c
File diff suppressed because it is too large
Load Diff
28
py/compile.h
28
py/compile.h
@@ -1,7 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// These must fit in 8 bits; see scope.h
|
||||
enum {
|
||||
MP_EMIT_OPT_NONE,
|
||||
MP_EMIT_OPT_BYTE_CODE,
|
||||
MP_EMIT_OPT_BYTECODE,
|
||||
MP_EMIT_OPT_NATIVE_PYTHON,
|
||||
MP_EMIT_OPT_VIPER,
|
||||
MP_EMIT_OPT_ASM_THUMB,
|
||||
|
||||
51
py/emit.h
51
py/emit.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Notes on passes:
|
||||
* We don't know exactly the opcodes in pass 1 because they depend on the
|
||||
* closing over of variables (LOAD_CLOSURE, BUILD_TUPLE, MAKE_CLOSURE), which
|
||||
@@ -9,18 +35,25 @@
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
PASS_1 = 1, // work out id's and their kind, and number of labels
|
||||
PASS_2 = 2, // work out stack size and code size and label offsets
|
||||
PASS_3 = 3, // emit code
|
||||
MP_PASS_SCOPE = 1, // work out id's and their kind, and number of labels
|
||||
MP_PASS_STACK_SIZE = 2, // work out maximum stack size
|
||||
MP_PASS_CODE_SIZE = 3, // work out code size and label offsets
|
||||
MP_PASS_EMIT = 4, // emit code
|
||||
} pass_kind_t;
|
||||
|
||||
#define MP_EMIT_STAR_FLAG_SINGLE (0x01)
|
||||
#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)
|
||||
|
||||
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
|
||||
|
||||
#define MP_EMIT_NATIVE_TYPE_ENABLE (0)
|
||||
#define MP_EMIT_NATIVE_TYPE_RETURN (1)
|
||||
#define MP_EMIT_NATIVE_TYPE_ARG (2)
|
||||
|
||||
typedef struct _emit_t emit_t;
|
||||
|
||||
typedef struct _emit_method_table_t {
|
||||
void (*set_native_types)(emit_t *emit, bool do_native_types);
|
||||
void (*set_native_type)(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2);
|
||||
void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
|
||||
void (*end_pass)(emit_t *emit);
|
||||
bool (*last_emit_was_return_value)(emit_t *emit);
|
||||
@@ -36,7 +69,7 @@ typedef struct _emit_method_table_t {
|
||||
void (*import_from)(emit_t *emit, qstr qstr);
|
||||
void (*import_star)(emit_t *emit);
|
||||
void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);
|
||||
void (*load_const_small_int)(emit_t *emit, machine_int_t arg);
|
||||
void (*load_const_small_int)(emit_t *emit, mp_int_t arg);
|
||||
void (*load_const_int)(emit_t *emit, qstr qstr);
|
||||
void (*load_const_dec)(emit_t *emit, qstr qstr);
|
||||
void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes);
|
||||
@@ -105,6 +138,11 @@ typedef struct _emit_method_table_t {
|
||||
void (*yield_value)(emit_t *emit);
|
||||
void (*yield_from)(emit_t *emit);
|
||||
|
||||
// these methods are used to control entry to/exit from an exception handler
|
||||
// they may or may not emit code
|
||||
void (*start_except_handler)(emit_t *emit);
|
||||
void (*end_except_handler)(emit_t *emit);
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// these methods are only needed for emitcpy
|
||||
void (*load_const_verbatim_str)(emit_t *emit, const char *str);
|
||||
@@ -123,17 +161,20 @@ extern const emit_method_table_t emit_cpython_method_table;
|
||||
extern const emit_method_table_t emit_bc_method_table;
|
||||
extern const emit_method_table_t emit_native_x64_method_table;
|
||||
extern const emit_method_table_t emit_native_thumb_method_table;
|
||||
extern const emit_method_table_t emit_native_arm_method_table;
|
||||
|
||||
emit_t *emit_pass1_new(void);
|
||||
emit_t *emit_cpython_new(uint max_num_labels);
|
||||
emit_t *emit_bc_new(uint max_num_labels);
|
||||
emit_t *emit_native_x64_new(uint max_num_labels);
|
||||
emit_t *emit_native_thumb_new(uint max_num_labels);
|
||||
emit_t *emit_native_arm_new(uint max_num_labels);
|
||||
|
||||
void emit_pass1_free(emit_t *emit);
|
||||
void emit_bc_free(emit_t *emit);
|
||||
void emit_native_x64_free(emit_t *emit);
|
||||
void emit_native_thumb_free(emit_t *emit);
|
||||
void emit_native_arm_free(emit_t *emit);
|
||||
|
||||
typedef struct _emit_inline_asm_t emit_inline_asm_t;
|
||||
|
||||
|
||||
423
py/emitbc.c
423
py/emitbc.c
@@ -1,11 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -18,10 +44,14 @@
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
|
||||
#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7)
|
||||
#define DUMMY_DATA_SIZE (BYTES_FOR_INT)
|
||||
|
||||
struct _emit_t {
|
||||
pass_kind_t pass;
|
||||
pass_kind_t pass : 8;
|
||||
uint last_emit_was_return_value : 8;
|
||||
|
||||
int stack_size;
|
||||
bool last_emit_was_return_value;
|
||||
|
||||
scope_t *scope;
|
||||
|
||||
@@ -33,10 +63,11 @@ struct _emit_t {
|
||||
|
||||
uint code_info_offset;
|
||||
uint code_info_size;
|
||||
uint byte_code_offset;
|
||||
uint byte_code_size;
|
||||
uint bytecode_offset;
|
||||
uint bytecode_size;
|
||||
byte *code_base; // stores both byte code and code info
|
||||
byte dummy_data[8];
|
||||
// Accessed as uint, so must be aligned as such
|
||||
byte dummy_data[DUMMY_DATA_SIZE];
|
||||
};
|
||||
|
||||
STATIC void emit_bc_rot_two(emit_t *emit);
|
||||
@@ -57,7 +88,7 @@ void emit_bc_free(emit_t *emit) {
|
||||
// all functions must go through this one to emit code info
|
||||
STATIC byte* emit_get_cur_to_write_code_info(emit_t* emit, int num_bytes_to_write) {
|
||||
//printf("emit %d\n", num_bytes_to_write);
|
||||
if (emit->pass < PASS_3) {
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
emit->code_info_offset += num_bytes_to_write;
|
||||
return emit->dummy_data;
|
||||
} else {
|
||||
@@ -69,7 +100,7 @@ STATIC byte* emit_get_cur_to_write_code_info(emit_t* emit, int num_bytes_to_writ
|
||||
}
|
||||
|
||||
STATIC void emit_align_code_info_to_machine_word(emit_t* emit) {
|
||||
emit->code_info_offset = (emit->code_info_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
emit->code_info_offset = (emit->code_info_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
|
||||
}
|
||||
|
||||
STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
|
||||
@@ -84,68 +115,80 @@ STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
STATIC void emit_write_code_info_bytes_lines(emit_t* emit, uint bytes_to_skip, uint lines_to_skip) {
|
||||
assert(bytes_to_skip > 0 || lines_to_skip > 0);
|
||||
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
|
||||
while (bytes_to_skip > 0 || lines_to_skip > 0) {
|
||||
uint b = MIN(bytes_to_skip, 31);
|
||||
uint l = MIN(lines_to_skip, 7);
|
||||
mp_uint_t b, l;
|
||||
if (lines_to_skip <= 6) {
|
||||
// use 0b0LLBBBBB encoding
|
||||
b = MIN(bytes_to_skip, 0x1f);
|
||||
l = MIN(lines_to_skip, 0x3);
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
|
||||
} else {
|
||||
// use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)
|
||||
b = MIN(bytes_to_skip, 0xf);
|
||||
l = MIN(lines_to_skip, 0x7ff);
|
||||
byte *ci = emit_get_cur_to_write_code_info(emit, 2);
|
||||
ci[0] = 0x80 | b | ((l >> 4) & 0x70);
|
||||
ci[1] = l;
|
||||
}
|
||||
bytes_to_skip -= b;
|
||||
lines_to_skip -= l;
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// all functions must go through this one to emit byte code
|
||||
STATIC byte* emit_get_cur_to_write_byte_code(emit_t* emit, int num_bytes_to_write) {
|
||||
STATIC byte* emit_get_cur_to_write_bytecode(emit_t* emit, int num_bytes_to_write) {
|
||||
//printf("emit %d\n", num_bytes_to_write);
|
||||
if (emit->pass < PASS_3) {
|
||||
emit->byte_code_offset += num_bytes_to_write;
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
emit->bytecode_offset += num_bytes_to_write;
|
||||
return emit->dummy_data;
|
||||
} else {
|
||||
assert(emit->byte_code_offset + num_bytes_to_write <= emit->byte_code_size);
|
||||
byte *c = emit->code_base + emit->code_info_size + emit->byte_code_offset;
|
||||
emit->byte_code_offset += num_bytes_to_write;
|
||||
assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size);
|
||||
byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset;
|
||||
emit->bytecode_offset += num_bytes_to_write;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_align_byte_code_to_machine_word(emit_t* emit) {
|
||||
emit->byte_code_offset = (emit->byte_code_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
STATIC void emit_align_bytecode_to_machine_word(emit_t* emit) {
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
|
||||
}
|
||||
|
||||
STATIC void emit_write_byte_code_byte(emit_t* emit, byte b1) {
|
||||
byte* c = emit_get_cur_to_write_byte_code(emit, 1);
|
||||
STATIC void emit_write_bytecode_byte(emit_t* emit, byte b1) {
|
||||
byte* c = emit_get_cur_to_write_bytecode(emit, 1);
|
||||
c[0] = b1;
|
||||
}
|
||||
|
||||
STATIC void emit_write_byte_code_byte_byte(emit_t* emit, byte b1, uint b2) {
|
||||
STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, uint b2) {
|
||||
assert((b2 & (~0xff)) == 0);
|
||||
byte* c = emit_get_cur_to_write_byte_code(emit, 2);
|
||||
byte* c = emit_get_cur_to_write_bytecode(emit, 2);
|
||||
c[0] = b1;
|
||||
c[1] = b2;
|
||||
}
|
||||
|
||||
STATIC void emit_write_byte_code_uint(emit_t* emit, uint num) {
|
||||
STATIC void emit_write_bytecode_uint(emit_t* emit, uint num) {
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
byte buf[(BYTES_PER_WORD * 8 + 6) / 7];
|
||||
byte buf[BYTES_FOR_INT];
|
||||
byte *p = buf + sizeof(buf);
|
||||
// We encode in little-ending order, but store in big-endian, to help decoding
|
||||
do {
|
||||
*--p = num & 0x7f;
|
||||
num >>= 7;
|
||||
} while (num != 0);
|
||||
byte* c = emit_get_cur_to_write_byte_code(emit, buf + sizeof(buf) - p);
|
||||
byte* c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);
|
||||
while (p != buf + sizeof(buf) - 1) {
|
||||
*c++ = *p++ | 0x80;
|
||||
}
|
||||
*c = *p;
|
||||
}
|
||||
|
||||
// Similar to emit_write_byte_code_uint(), just some extra handling to encode sign
|
||||
STATIC void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t num) {
|
||||
emit_write_byte_code_byte(emit, b1);
|
||||
// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign
|
||||
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, mp_int_t num) {
|
||||
emit_write_bytecode_byte(emit, b1);
|
||||
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
byte buf[(BYTES_PER_WORD * 8 + 6) / 7];
|
||||
byte buf[BYTES_FOR_INT];
|
||||
byte *p = buf + sizeof(buf);
|
||||
// We encode in little-ending order, but store in big-endian, to help decoding
|
||||
do {
|
||||
@@ -160,67 +203,69 @@ STATIC void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t n
|
||||
*--p = 0;
|
||||
}
|
||||
|
||||
byte* c = emit_get_cur_to_write_byte_code(emit, buf + sizeof(buf) - p);
|
||||
byte* c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);
|
||||
while (p != buf + sizeof(buf) - 1) {
|
||||
*c++ = *p++ | 0x80;
|
||||
}
|
||||
*c = *p;
|
||||
}
|
||||
|
||||
STATIC void emit_write_byte_code_byte_uint(emit_t* emit, byte b, uint num) {
|
||||
emit_write_byte_code_byte(emit, b);
|
||||
emit_write_byte_code_uint(emit, num);
|
||||
STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, uint num) {
|
||||
emit_write_bytecode_byte(emit, b);
|
||||
emit_write_bytecode_uint(emit, num);
|
||||
}
|
||||
|
||||
// aligns the pointer so it is friendly to GC
|
||||
STATIC void emit_write_byte_code_byte_ptr(emit_t* emit, byte b, void *ptr) {
|
||||
emit_write_byte_code_byte(emit, b);
|
||||
emit_align_byte_code_to_machine_word(emit);
|
||||
machine_uint_t *c = (machine_uint_t*)emit_get_cur_to_write_byte_code(emit, sizeof(machine_uint_t));
|
||||
*c = (machine_uint_t)ptr;
|
||||
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
|
||||
emit_write_bytecode_byte(emit, b);
|
||||
emit_align_bytecode_to_machine_word(emit);
|
||||
mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
|
||||
// Verify thar c is already uint-aligned
|
||||
assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
|
||||
*c = (mp_uint_t)ptr;
|
||||
}
|
||||
|
||||
/* currently unused
|
||||
STATIC void emit_write_byte_code_byte_uint_uint(emit_t* emit, byte b, uint num1, uint num2) {
|
||||
emit_write_byte_code_byte(emit, b);
|
||||
emit_write_byte_code_byte_uint(emit, num1);
|
||||
emit_write_byte_code_byte_uint(emit, num2);
|
||||
STATIC void emit_write_bytecode_byte_uint_uint(emit_t* emit, byte b, uint num1, uint num2) {
|
||||
emit_write_bytecode_byte(emit, b);
|
||||
emit_write_bytecode_byte_uint(emit, num1);
|
||||
emit_write_bytecode_byte_uint(emit, num2);
|
||||
}
|
||||
*/
|
||||
|
||||
STATIC void emit_write_byte_code_byte_qstr(emit_t* emit, byte b, qstr qstr) {
|
||||
emit_write_byte_code_byte_uint(emit, b, qstr);
|
||||
STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qstr) {
|
||||
emit_write_bytecode_byte_uint(emit, b, qstr);
|
||||
}
|
||||
|
||||
// unsigned labels are relative to ip following this instruction, stored as 16 bits
|
||||
STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, uint label) {
|
||||
uint byte_code_offset;
|
||||
if (emit->pass < PASS_3) {
|
||||
byte_code_offset = 0;
|
||||
STATIC void emit_write_bytecode_byte_unsigned_label(emit_t* emit, byte b1, uint label) {
|
||||
uint bytecode_offset;
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
bytecode_offset = 0;
|
||||
} else {
|
||||
byte_code_offset = emit->label_offsets[label] - emit->byte_code_offset - 3;
|
||||
bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3;
|
||||
}
|
||||
byte *c = emit_get_cur_to_write_byte_code(emit, 3);
|
||||
byte *c = emit_get_cur_to_write_bytecode(emit, 3);
|
||||
c[0] = b1;
|
||||
c[1] = byte_code_offset;
|
||||
c[2] = byte_code_offset >> 8;
|
||||
c[1] = bytecode_offset;
|
||||
c[2] = bytecode_offset >> 8;
|
||||
}
|
||||
|
||||
// signed labels are relative to ip following this instruction, stored as 16 bits, in excess
|
||||
STATIC void emit_write_byte_code_byte_signed_label(emit_t* emit, byte b1, uint label) {
|
||||
int byte_code_offset;
|
||||
if (emit->pass < PASS_3) {
|
||||
byte_code_offset = 0;
|
||||
STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, uint label) {
|
||||
int bytecode_offset;
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
bytecode_offset = 0;
|
||||
} else {
|
||||
byte_code_offset = emit->label_offsets[label] - emit->byte_code_offset - 3 + 0x8000;
|
||||
bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000;
|
||||
}
|
||||
byte* c = emit_get_cur_to_write_byte_code(emit, 3);
|
||||
byte* c = emit_get_cur_to_write_bytecode(emit, 3);
|
||||
c[0] = b1;
|
||||
c[1] = byte_code_offset;
|
||||
c[2] = byte_code_offset >> 8;
|
||||
c[1] = bytecode_offset;
|
||||
c[2] = bytecode_offset >> 8;
|
||||
}
|
||||
|
||||
STATIC void emit_bc_set_native_types(emit_t *emit, bool do_native_types) {
|
||||
STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
}
|
||||
|
||||
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
@@ -230,16 +275,16 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
emit->scope = scope;
|
||||
emit->last_source_line_offset = 0;
|
||||
emit->last_source_line = 1;
|
||||
if (pass == PASS_2) {
|
||||
if (pass < MP_PASS_EMIT) {
|
||||
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(uint));
|
||||
}
|
||||
emit->byte_code_offset = 0;
|
||||
emit->bytecode_offset = 0;
|
||||
emit->code_info_offset = 0;
|
||||
|
||||
// write code info size (don't know size at this stage in PASS_2 so need to use maximum space (4 bytes) to write it)
|
||||
// write code info size; use maximum space (4 bytes) to write it; TODO possible optimise this
|
||||
{
|
||||
byte* c = emit_get_cur_to_write_code_info(emit, 4);
|
||||
machine_uint_t s = emit->code_info_size;
|
||||
mp_uint_t s = emit->code_info_size;
|
||||
c[0] = s & 0xff;
|
||||
c[1] = (s >> 8) & 0xff;
|
||||
c[2] = (s >> 16) & 0xff;
|
||||
@@ -252,7 +297,7 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
|
||||
// bytecode prelude: local state size and exception stack size; 16 bit uints for now
|
||||
{
|
||||
byte* c = emit_get_cur_to_write_byte_code(emit, 4);
|
||||
byte* c = emit_get_cur_to_write_bytecode(emit, 4);
|
||||
uint n_state = scope->num_locals + scope->stack_size;
|
||||
if (n_state == 0) {
|
||||
// Need at least 1 entry in the state, in the case an exception is
|
||||
@@ -275,11 +320,11 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
}
|
||||
}
|
||||
assert(num_cell <= 255);
|
||||
emit_write_byte_code_byte(emit, num_cell); // write number of locals that are cells
|
||||
emit_write_bytecode_byte(emit, num_cell); // write number of locals that are cells
|
||||
for (int i = 0; i < scope->id_info_len; i++) {
|
||||
id_info_t *id = &scope->id_info[i];
|
||||
if (id->kind == ID_INFO_KIND_CELL) {
|
||||
emit_write_byte_code_byte(emit, id->local_num); // write the local which should be converted to a cell
|
||||
emit_write_bytecode_byte(emit, id->local_num); // write the local which should be converted to a cell
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,21 +336,21 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
|
||||
}
|
||||
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = 0; // end of line number info
|
||||
emit_align_code_info_to_machine_word(emit); // align so that following byte_code is aligned
|
||||
emit_align_code_info_to_machine_word(emit); // align so that following bytecode is aligned
|
||||
|
||||
if (emit->pass == PASS_2) {
|
||||
if (emit->pass == MP_PASS_CODE_SIZE) {
|
||||
// calculate size of code in bytes
|
||||
emit->code_info_size = emit->code_info_offset;
|
||||
emit->byte_code_size = emit->byte_code_offset;
|
||||
emit->code_base = m_new0(byte, emit->code_info_size + emit->byte_code_size);
|
||||
emit->bytecode_size = emit->bytecode_offset;
|
||||
emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
|
||||
|
||||
} else if (emit->pass == PASS_3) {
|
||||
} else if (emit->pass == MP_PASS_EMIT) {
|
||||
qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
|
||||
arg_names[i] = emit->scope->id_info[i].qstr;
|
||||
}
|
||||
mp_emit_glue_assign_byte_code(emit->scope->raw_code, emit->code_base,
|
||||
emit->code_info_size + emit->byte_code_size,
|
||||
mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
|
||||
emit->code_info_size + emit->bytecode_size,
|
||||
emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names,
|
||||
emit->scope->scope_flags);
|
||||
}
|
||||
@@ -320,14 +365,17 @@ STATIC void emit_bc_adjust_stack_size(emit_t *emit, int delta) {
|
||||
}
|
||||
|
||||
STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
|
||||
//printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->byte_code_offset);
|
||||
//printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset);
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
if (mp_optimise_value >= 3) {
|
||||
// If we compile with -O3, don't store line numbers.
|
||||
return;
|
||||
}
|
||||
if (source_line > emit->last_source_line) {
|
||||
uint bytes_to_skip = emit->byte_code_offset - emit->last_source_line_offset;
|
||||
uint bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
|
||||
uint lines_to_skip = source_line - emit->last_source_line;
|
||||
emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);
|
||||
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
|
||||
emit->last_source_line_offset = emit->byte_code_offset;
|
||||
emit->last_source_line_offset = emit->bytecode_offset;
|
||||
emit->last_source_line = source_line;
|
||||
}
|
||||
#endif
|
||||
@@ -357,170 +405,170 @@ STATIC void emit_bc_pre(emit_t *emit, int stack_size_delta) {
|
||||
STATIC void emit_bc_label_assign(emit_t *emit, uint l) {
|
||||
emit_bc_pre(emit, 0);
|
||||
assert(l < emit->max_num_labels);
|
||||
if (emit->pass == PASS_2) {
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(emit->label_offsets[l] == -1);
|
||||
emit->label_offsets[l] = emit->byte_code_offset;
|
||||
} else if (emit->pass == PASS_3) {
|
||||
// ensure label offset has not changed from PASS_2 to PASS_3
|
||||
//printf("l%d: (at %d vs %d)\n", l, emit->byte_code_offset, emit->label_offsets[l]);
|
||||
assert(emit->label_offsets[l] == emit->byte_code_offset);
|
||||
emit->label_offsets[l] = emit->bytecode_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
|
||||
//printf("l%d: (at %d vs %d)\n", l, emit->bytecode_offset, emit->label_offsets[l]);
|
||||
assert(emit->label_offsets[l] == emit->bytecode_offset);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_import_name(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_IMPORT_NAME, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_import_from(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_IMPORT_FROM, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_import_star(emit_t *emit) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_IMPORT_STAR);
|
||||
emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
emit_bc_pre(emit, 1);
|
||||
switch (tok) {
|
||||
case MP_TOKEN_KW_FALSE: emit_write_byte_code_byte(emit, MP_BC_LOAD_CONST_FALSE); break;
|
||||
case MP_TOKEN_KW_NONE: emit_write_byte_code_byte(emit, MP_BC_LOAD_CONST_NONE); break;
|
||||
case MP_TOKEN_KW_TRUE: emit_write_byte_code_byte(emit, MP_BC_LOAD_CONST_TRUE); break;
|
||||
case MP_TOKEN_ELLIPSIS: emit_write_byte_code_byte(emit, MP_BC_LOAD_CONST_ELLIPSIS); break;
|
||||
case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break;
|
||||
case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break;
|
||||
case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break;
|
||||
case MP_TOKEN_ELLIPSIS: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_ELLIPSIS); break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_int(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_CONST_INT, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_INT, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_dec(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_CONST_DEC, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_DEC, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
|
||||
emit_bc_pre(emit, 1);
|
||||
if (bytes) {
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_CONST_BYTES, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_BYTES, qstr);
|
||||
} else {
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qstr);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_null(emit_t *emit) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_LOAD_NULL);
|
||||
emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL);
|
||||
};
|
||||
|
||||
STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
|
||||
assert(local_num >= 0);
|
||||
emit_bc_pre(emit, 1);
|
||||
switch (local_num) {
|
||||
case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break;
|
||||
case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break;
|
||||
case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break;
|
||||
default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
|
||||
case 0: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_0); break;
|
||||
case 1: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_1); break;
|
||||
case 2: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_2); break;
|
||||
default: emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_deref(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_name(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_NAME, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_global(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_attr(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_ATTR, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_method(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_METHOD, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_METHOD, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_build_class(emit_t *emit) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_LOAD_BUILD_CLASS);
|
||||
emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_subscr(emit_t *emit) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_LOAD_SUBSCR);
|
||||
emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
assert(local_num >= 0);
|
||||
emit_bc_pre(emit, -1);
|
||||
switch (local_num) {
|
||||
case 0: emit_write_byte_code_byte(emit, MP_BC_STORE_FAST_0); break;
|
||||
case 1: emit_write_byte_code_byte(emit, MP_BC_STORE_FAST_1); break;
|
||||
case 2: emit_write_byte_code_byte(emit, MP_BC_STORE_FAST_2); break;
|
||||
default: emit_write_byte_code_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); break;
|
||||
case 0: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_0); break;
|
||||
case 1: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_1); break;
|
||||
case 2: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_2); break;
|
||||
default: emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); break;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_deref(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_name(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_STORE_NAME, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_global(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_STORE_GLOBAL, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_attr(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, -2);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_STORE_ATTR, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_subscr(emit_t *emit) {
|
||||
emit_bc_pre(emit, -3);
|
||||
emit_write_byte_code_byte(emit, MP_BC_STORE_SUBSCR);
|
||||
emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_deref(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_name(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_DELETE_NAME, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_global(emit_t *emit, qstr qstr) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qstr);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qstr);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_attr(emit_t *emit, qstr qstr) {
|
||||
@@ -537,97 +585,101 @@ STATIC void emit_bc_delete_subscr(emit_t *emit) {
|
||||
|
||||
STATIC void emit_bc_dup_top(emit_t *emit) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_DUP_TOP);
|
||||
emit_write_bytecode_byte(emit, MP_BC_DUP_TOP);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_dup_top_two(emit_t *emit) {
|
||||
emit_bc_pre(emit, 2);
|
||||
emit_write_byte_code_byte(emit, MP_BC_DUP_TOP_TWO);
|
||||
emit_write_bytecode_byte(emit, MP_BC_DUP_TOP_TWO);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_pop_top(emit_t *emit) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_POP_TOP);
|
||||
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_rot_two(emit_t *emit) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_ROT_TWO);
|
||||
emit_write_bytecode_byte(emit, MP_BC_ROT_TWO);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_rot_three(emit_t *emit) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_ROT_THREE);
|
||||
emit_write_bytecode_byte(emit, MP_BC_ROT_THREE);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_jump(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP, label);
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_pop_jump_if_true(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label);
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_pop_jump_if_false(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label);
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label);
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label);
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
|
||||
if (except_depth == 0) {
|
||||
emit_bc_jump(emit, label);
|
||||
} else {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label);
|
||||
emit_write_byte_code_byte(emit, except_depth);
|
||||
if (label & MP_EMIT_BREAK_FROM_FOR) {
|
||||
// need to pop the iterator if we are breaking out of a for loop
|
||||
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
|
||||
}
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
|
||||
} else {
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
|
||||
emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_setup_with(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, 7);
|
||||
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
|
||||
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_with_cleanup(emit_t *emit) {
|
||||
emit_bc_pre(emit, -7);
|
||||
emit_write_byte_code_byte(emit, MP_BC_WITH_CLEANUP);
|
||||
emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_setup_except(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
|
||||
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_setup_finally(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
|
||||
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_end_finally(emit_t *emit) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte(emit, MP_BC_END_FINALLY);
|
||||
emit_write_bytecode_byte(emit, MP_BC_END_FINALLY);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_get_iter(emit_t *emit) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_GET_ITER);
|
||||
emit_write_bytecode_byte(emit, MP_BC_GET_ITER);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_for_iter(emit_t *emit, uint label) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_FOR_ITER, label);
|
||||
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_for_iter_end(emit_t *emit) {
|
||||
@@ -636,23 +688,23 @@ STATIC void emit_bc_for_iter_end(emit_t *emit) {
|
||||
|
||||
STATIC void emit_bc_pop_block(emit_t *emit) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_POP_BLOCK);
|
||||
emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_pop_except(emit_t *emit) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_POP_EXCEPT);
|
||||
emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
if (op == MP_UNARY_OP_NOT) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_byte(emit, MP_BC_UNARY_OP, MP_UNARY_OP_BOOL);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, MP_UNARY_OP_BOOL);
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_NOT);
|
||||
emit_write_bytecode_byte(emit, MP_BC_NOT);
|
||||
} else {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte_byte(emit, MP_BC_UNARY_OP, op);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, op);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -666,98 +718,98 @@ STATIC void emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
op = MP_BINARY_OP_IS;
|
||||
}
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_byte(emit, MP_BC_BINARY_OP, op);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_BINARY_OP, op);
|
||||
if (invert) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_byte_code_byte(emit, MP_BC_NOT);
|
||||
emit_write_bytecode_byte(emit, MP_BC_NOT);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_build_tuple(emit_t *emit, int n_args) {
|
||||
assert(n_args >= 0);
|
||||
emit_bc_pre(emit, 1 - n_args);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_build_list(emit_t *emit, int n_args) {
|
||||
assert(n_args >= 0);
|
||||
emit_bc_pre(emit, 1 - n_args);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_BUILD_LIST, n_args);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_list_append(emit_t *emit, int list_stack_index) {
|
||||
assert(list_stack_index >= 0);
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_LIST_APPEND, list_stack_index);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_LIST_APPEND, list_stack_index);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_build_map(emit_t *emit, int n_args) {
|
||||
assert(n_args >= 0);
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_BUILD_MAP, n_args);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_map(emit_t *emit) {
|
||||
emit_bc_pre(emit, -2);
|
||||
emit_write_byte_code_byte(emit, MP_BC_STORE_MAP);
|
||||
emit_write_bytecode_byte(emit, MP_BC_STORE_MAP);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_map_add(emit_t *emit, int map_stack_index) {
|
||||
assert(map_stack_index >= 0);
|
||||
emit_bc_pre(emit, -2);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_MAP_ADD, map_stack_index);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_MAP_ADD, map_stack_index);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_build_set(emit_t *emit, int n_args) {
|
||||
assert(n_args >= 0);
|
||||
emit_bc_pre(emit, 1 - n_args);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_BUILD_SET, n_args);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_set_add(emit_t *emit, int set_stack_index) {
|
||||
assert(set_stack_index >= 0);
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_SET_ADD, set_stack_index);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_SET_ADD, set_stack_index);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_build_slice(emit_t *emit, int n_args) {
|
||||
assert(n_args >= 0);
|
||||
emit_bc_pre(emit, 1 - n_args);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_BUILD_SLICE, n_args);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_unpack_sequence(emit_t *emit, int n_args) {
|
||||
assert(n_args >= 0);
|
||||
emit_bc_pre(emit, -1 + n_args);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_unpack_ex(emit_t *emit, int n_left, int n_right) {
|
||||
assert(n_left >=0 && n_right >= 0);
|
||||
emit_bc_pre(emit, -1 + n_left + n_right + 1);
|
||||
emit_write_byte_code_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8));
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8));
|
||||
}
|
||||
|
||||
STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_FUNCTION, scope->raw_code);
|
||||
emit_write_bytecode_byte_ptr(emit, MP_BC_MAKE_FUNCTION, scope->raw_code);
|
||||
} else {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);
|
||||
emit_write_bytecode_byte_ptr(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) {
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
emit_bc_pre(emit, -n_closed_over + 1);
|
||||
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_CLOSURE, scope->raw_code);
|
||||
emit_write_byte_code_byte(emit, n_closed_over);
|
||||
emit_write_bytecode_byte_ptr(emit, MP_BC_MAKE_CLOSURE, scope->raw_code);
|
||||
emit_write_bytecode_byte(emit, n_closed_over);
|
||||
} else {
|
||||
assert(n_closed_over <= 255);
|
||||
emit_bc_pre(emit, -2 - n_closed_over + 1);
|
||||
emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);
|
||||
emit_write_byte_code_byte(emit, n_closed_over);
|
||||
emit_write_bytecode_byte_ptr(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);
|
||||
emit_write_bytecode_byte(emit, n_closed_over);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,10 +824,10 @@ STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uin
|
||||
emit_bc_load_null(emit);
|
||||
}
|
||||
emit_bc_pre(emit, stack_adj - n_positional - 2 * n_keyword - 2);
|
||||
emit_write_byte_code_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
|
||||
emit_write_bytecode_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
|
||||
} else {
|
||||
emit_bc_pre(emit, stack_adj - n_positional - 2 * n_keyword);
|
||||
emit_write_byte_code_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
|
||||
emit_write_bytecode_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,33 +842,37 @@ STATIC void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, u
|
||||
STATIC void emit_bc_return_value(emit_t *emit) {
|
||||
emit_bc_pre(emit, -1);
|
||||
emit->last_emit_was_return_value = true;
|
||||
emit_write_byte_code_byte(emit, MP_BC_RETURN_VALUE);
|
||||
emit_write_bytecode_byte(emit, MP_BC_RETURN_VALUE);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_raise_varargs(emit_t *emit, int n_args) {
|
||||
assert(0 <= n_args && n_args <= 2);
|
||||
emit_bc_pre(emit, -n_args);
|
||||
emit_write_byte_code_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args);
|
||||
emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_yield_value(emit_t *emit) {
|
||||
emit_bc_pre(emit, 0);
|
||||
if (emit->pass == PASS_2) {
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
}
|
||||
emit_write_byte_code_byte(emit, MP_BC_YIELD_VALUE);
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_yield_from(emit_t *emit) {
|
||||
emit_bc_pre(emit, -1);
|
||||
if (emit->pass == PASS_2) {
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
}
|
||||
emit_write_byte_code_byte(emit, MP_BC_YIELD_FROM);
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_start_except_handler(emit_t *emit) {
|
||||
emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
|
||||
}
|
||||
|
||||
STATIC void emit_bc_end_except_handler(emit_t *emit) {
|
||||
emit_bc_adjust_stack_size(emit, -5); // stack adjust
|
||||
}
|
||||
|
||||
const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_set_native_types,
|
||||
emit_bc_set_native_type,
|
||||
emit_bc_start_pass,
|
||||
emit_bc_end_pass,
|
||||
emit_bc_last_emit_was_return_value,
|
||||
@@ -900,6 +956,9 @@ const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_raise_varargs,
|
||||
emit_bc_yield_value,
|
||||
emit_bc_yield_from,
|
||||
|
||||
emit_bc_start_except_handler,
|
||||
emit_bc_end_except_handler,
|
||||
};
|
||||
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
@@ -1,9 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
|
||||
231
py/emitcpy.c
231
py/emitcpy.c
@@ -1,11 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -20,7 +46,7 @@
|
||||
|
||||
struct _emit_t {
|
||||
int pass;
|
||||
int byte_code_offset;
|
||||
int bytecode_offset;
|
||||
int stack_size;
|
||||
bool last_emit_was_return_value;
|
||||
|
||||
@@ -37,16 +63,16 @@ emit_t *emit_cpython_new(uint max_num_labels) {
|
||||
return emit;
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_native_types(emit_t *emit, bool do_native_types) {
|
||||
STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
emit->pass = pass;
|
||||
emit->byte_code_offset = 0;
|
||||
emit->bytecode_offset = 0;
|
||||
emit->stack_size = 0;
|
||||
emit->last_emit_was_return_value = false;
|
||||
emit->scope = scope;
|
||||
if (pass == PASS_2) {
|
||||
if (pass < MP_PASS_EMIT) {
|
||||
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(int));
|
||||
}
|
||||
}
|
||||
@@ -82,60 +108,60 @@ STATIC void emit_cpy_delete_id(emit_t *emit, qstr qstr) {
|
||||
}
|
||||
|
||||
// TODO: module-polymorphic function (read: name clash if made global)
|
||||
static void emit_pre(emit_t *emit, int stack_size_delta, int byte_code_size) {
|
||||
static void emit_pre(emit_t *emit, int stack_size_delta, int bytecode_size) {
|
||||
emit->stack_size += stack_size_delta;
|
||||
if (emit->stack_size > emit->scope->stack_size) {
|
||||
emit->scope->stack_size = emit->stack_size;
|
||||
}
|
||||
emit->last_emit_was_return_value = false;
|
||||
if (emit->pass == PASS_3 && byte_code_size > 0) {
|
||||
if (emit->byte_code_offset >= 1000) {
|
||||
printf("%d ", emit->byte_code_offset);
|
||||
if (emit->pass == MP_PASS_EMIT && bytecode_size > 0) {
|
||||
if (emit->bytecode_offset >= 1000) {
|
||||
printf("%d ", emit->bytecode_offset);
|
||||
} else {
|
||||
printf("% 4d ", emit->byte_code_offset);
|
||||
printf("% 4d ", emit->bytecode_offset);
|
||||
}
|
||||
}
|
||||
emit->byte_code_offset += byte_code_size;
|
||||
emit->bytecode_offset += bytecode_size;
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_label_assign(emit_t *emit, uint l) {
|
||||
emit_pre(emit, 0, 0);
|
||||
assert(l < emit->max_num_labels);
|
||||
if (emit->pass == PASS_2) {
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(emit->label_offsets[l] == -1);
|
||||
emit->label_offsets[l] = emit->byte_code_offset;
|
||||
} else if (emit->pass == PASS_3) {
|
||||
// ensure label offset has not changed from PASS_2 to PASS_3
|
||||
assert(emit->label_offsets[l] == emit->byte_code_offset);
|
||||
//printf("l%d: (at %d)\n", l, emit->byte_code_offset);
|
||||
emit->label_offsets[l] = emit->bytecode_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
|
||||
assert(emit->label_offsets[l] == emit->bytecode_offset);
|
||||
//printf("l%d: (at %d)\n", l, emit->bytecode_offset);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_import_name(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("IMPORT_NAME %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_import_from(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("IMPORT_FROM %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_import_star(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("IMPORT_STAR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST ");
|
||||
switch (tok) {
|
||||
case MP_TOKEN_KW_FALSE: printf("False"); break;
|
||||
@@ -147,23 +173,23 @@ STATIC void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST " INT_FMT "\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_int(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_dec(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
@@ -207,7 +233,7 @@ STATIC void print_quoted_str(qstr qstr, bool bytes) {
|
||||
|
||||
STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST ");
|
||||
print_quoted_str(qstr, bytes);
|
||||
printf("\n");
|
||||
@@ -221,35 +247,35 @@ STATIC void emit_cpy_load_null(emit_t *emit) {
|
||||
|
||||
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_FAST %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_deref(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_DEREF %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_name(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_NAME %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_global(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_GLOBAL %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_attr(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_ATTR %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
@@ -260,142 +286,142 @@ STATIC void emit_cpy_load_method(emit_t *emit, qstr qstr) {
|
||||
|
||||
STATIC void emit_cpy_load_build_class(emit_t *emit) {
|
||||
emit_pre(emit, 1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_BUILD_CLASS\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BINARY_SUBSCR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_FAST %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_deref(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_DEREF %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_name(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_NAME %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_global(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_GLOBAL %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_attr(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, -2, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_ATTR %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -3, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_SUBSCR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_FAST %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_deref(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_DEREF %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_name(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_NAME %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_global(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_GLOBAL %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_attr(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_ATTR %s\n", qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -2, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_SUBSCR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_dup_top(emit_t *emit) {
|
||||
emit_pre(emit, 1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DUP_TOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_dup_top_two(emit_t *emit) {
|
||||
emit_pre(emit, 2, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DUP_TOP_TWO\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_top(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_TOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_rot_two(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("ROT_TWO\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_rot_three(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("ROT_THREE\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_jump(emit_t *emit, uint label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
int dest = emit->label_offsets[label];
|
||||
if (dest < emit->byte_code_offset) {
|
||||
if (dest < emit->bytecode_offset) {
|
||||
printf("JUMP_ABSOLUTE %d\n", emit->label_offsets[label]);
|
||||
} else {
|
||||
printf("JUMP_FORWARD %d\n", emit->label_offsets[label]);
|
||||
@@ -405,35 +431,35 @@ STATIC void emit_cpy_jump(emit_t *emit, uint label) {
|
||||
|
||||
STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, uint label) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_JUMP_IF_TRUE %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, uint label) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_JUMP_IF_FALSE %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, uint label) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("JUMP_IF_TRUE_OR_POP %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, uint label) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("JUMP_IF_FALSE_OR_POP %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_break_loop(emit_t *emit, uint label, int except_depth) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BREAK_LOOP\n");
|
||||
}
|
||||
}
|
||||
@@ -443,7 +469,7 @@ STATIC void emit_cpy_continue_loop(emit_t *emit, uint label, int except_depth) {
|
||||
emit_cpy_jump(emit, label);
|
||||
} else {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("CONTINUE_LOOP %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
@@ -451,49 +477,49 @@ STATIC void emit_cpy_continue_loop(emit_t *emit, uint label, int except_depth) {
|
||||
|
||||
STATIC void emit_cpy_setup_with(emit_t *emit, uint label) {
|
||||
emit_pre(emit, 7, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_WITH %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_with_cleanup(emit_t *emit) {
|
||||
emit_pre(emit, -7, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("WITH_CLEANUP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_except(emit_t *emit, uint label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_EXCEPT %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_finally(emit_t *emit, uint label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_FINALLY %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_finally(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("END_FINALLY\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_get_iter(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("GET_ITER\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_for_iter(emit_t *emit, uint label) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("FOR_ITER %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
@@ -504,21 +530,21 @@ STATIC void emit_cpy_for_iter_end(emit_t *emit) {
|
||||
|
||||
STATIC void emit_cpy_pop_block(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_BLOCK\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_except(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_EXCEPT\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_POSITIVE: printf("UNARY_POSITIVE\n"); break;
|
||||
case MP_UNARY_OP_NEGATIVE: printf("UNARY_NEGATIVE\n"); break;
|
||||
@@ -537,7 +563,7 @@ STATIC void emit_cpy_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
// CPython uses a byte code plus an argument for compare ops
|
||||
emit_pre(emit, -1, 3);
|
||||
}
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_OR: printf("BINARY_OR\n"); break;
|
||||
case MP_BINARY_OP_XOR: printf("BINARY_XOR\n"); break;
|
||||
@@ -581,77 +607,77 @@ STATIC void emit_cpy_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
|
||||
STATIC void emit_cpy_build_tuple(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_TUPLE %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_list(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_LIST %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_list_append(emit_t *emit, int list_index) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LIST_APPEND %d\n", list_index);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_map(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_MAP %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_map(emit_t *emit) {
|
||||
emit_pre(emit, -2, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_MAP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_map_add(emit_t *emit, int map_index) {
|
||||
emit_pre(emit, -2, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("MAP_ADD %d\n", map_index);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_set(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_SET %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_add(emit_t *emit, int set_index) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SET_ADD %d\n", set_index);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_slice(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_SLICE %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_unpack_sequence(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, -1 + n_args, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("UNPACK_SEQUENCE %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_unpack_ex(emit_t *emit, int n_left, int n_right) {
|
||||
emit_pre(emit, -1 + n_left + n_right + 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("UNPACK_EX %d\n", n_left | (n_right << 8));
|
||||
}
|
||||
}
|
||||
@@ -665,7 +691,7 @@ STATIC void emit_cpy_call_function(emit_t *emit, int n_positional, int n_keyword
|
||||
s += 1;
|
||||
}
|
||||
emit_pre(emit, -n_positional - 2 * n_keyword - s, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) {
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
|
||||
printf("CALL_FUNCTION_VAR_KW");
|
||||
@@ -690,26 +716,26 @@ STATIC void emit_cpy_call_method(emit_t *emit, int n_positional, int n_keyword,
|
||||
STATIC void emit_cpy_return_value(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
emit->last_emit_was_return_value = true;
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("RETURN_VALUE\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_raise_varargs(emit_t *emit, int n_args) {
|
||||
emit_pre(emit, -n_args, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("RAISE_VARARGS %d\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void load_cpy_const_code_and_name(emit_t *emit, qstr qstr) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST code %s\n", qstr_str(qstr));
|
||||
}
|
||||
// load qualified name
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST '");
|
||||
// code just to work out the qualname (or whatever it is)
|
||||
{
|
||||
@@ -736,7 +762,7 @@ STATIC void load_cpy_const_code_and_name(emit_t *emit, qstr qstr) {
|
||||
STATIC void emit_cpy_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
|
||||
load_cpy_const_code_and_name(emit, scope->simple_name);
|
||||
emit_pre(emit, -1 - n_pos_defaults - 2 * n_kw_defaults, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("MAKE_FUNCTION %d\n", (n_kw_defaults << 8) | n_pos_defaults);
|
||||
}
|
||||
}
|
||||
@@ -745,54 +771,58 @@ STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, uint n_closed_ov
|
||||
emit_cpy_build_tuple(emit, n_closed_over);
|
||||
load_cpy_const_code_and_name(emit, scope->simple_name);
|
||||
emit_pre(emit, -2 - n_pos_defaults - 2 * n_kw_defaults, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("MAKE_CLOSURE %d\n", (n_kw_defaults << 8) | n_pos_defaults);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_yield_value(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == PASS_2) {
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
}
|
||||
if (emit->pass == PASS_3) {
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("YIELD_VALUE\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_yield_from(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_2) {
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
}
|
||||
if (emit->pass == PASS_3) {
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("YIELD_FROM\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, -5); // stack adjust
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST %s\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CLOSURE %d %s\n", local_num, qstr_str(qstr));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_LOOP %d\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_set_native_types,
|
||||
emit_cpy_set_native_type,
|
||||
emit_cpy_start_pass,
|
||||
emit_cpy_end_pass,
|
||||
emit_cpy_last_emit_was_return_value,
|
||||
@@ -877,6 +907,9 @@ const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_yield_value,
|
||||
emit_cpy_yield_from,
|
||||
|
||||
emit_cpy_start_except_handler,
|
||||
emit_cpy_end_except_handler,
|
||||
|
||||
// emitcpy specific functions
|
||||
emit_cpy_load_const_verbatim_str,
|
||||
emit_cpy_load_closure,
|
||||
|
||||
147
py/emitglue.c
147
py/emitglue.c
@@ -1,11 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This code glues the code emitters to the runtime.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -23,32 +49,14 @@
|
||||
#define DEBUG_OP_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
#ifdef WRITE_CODE
|
||||
FILE *fp_write_code = NULL;
|
||||
#endif
|
||||
|
||||
void mp_emit_glue_init(void) {
|
||||
#ifdef WRITE_CODE
|
||||
fp_write_code = fopen("out-code", "wb");
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp_emit_glue_deinit(void) {
|
||||
#ifdef WRITE_CODE
|
||||
if (fp_write_code != NULL) {
|
||||
fclose(fp_write_code);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
|
||||
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
|
||||
rc->kind = MP_CODE_RESERVED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags) {
|
||||
rc->kind = MP_CODE_BYTE;
|
||||
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags) {
|
||||
rc->kind = MP_CODE_BYTECODE;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
rc->n_kwonly_args = n_kwonly_args;
|
||||
@@ -57,76 +65,54 @@ void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint
|
||||
rc->u_byte.len = len;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign byte code: code=%p len=%u n_pos_args=%d n_kwonly_args=%d flags=%x\n", code, len, n_pos_args, n_kwonly_args, scope_flags);
|
||||
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
|
||||
DEBUG_printf(" arg names:");
|
||||
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
|
||||
DEBUG_printf(" %s", qstr_str(arg_names[i]));
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
DEBUG_printf("\n");
|
||||
}
|
||||
DEBUG_printf(" %02x", code[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
mp_byte_code_print(code, len);
|
||||
#endif
|
||||
if (mp_verbose_flag > 0) {
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" %02x", code[i]);
|
||||
}
|
||||
printf("\n");
|
||||
mp_bytecode_print(rc, code, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
|
||||
rc->kind = MP_CODE_NATIVE;
|
||||
#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) {
|
||||
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
|
||||
rc->kind = kind;
|
||||
rc->scope_flags = 0;
|
||||
rc->n_pos_args = n_args;
|
||||
rc->u_native.fun = fun;
|
||||
rc->u_native.fun_data = fun_data;
|
||||
rc->u_native.type_sig = type_sig;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign native code: fun=%p len=%u n_args=%d\n", fun, len, n_args);
|
||||
byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
|
||||
for (mp_uint_t i = 0; i < fun_len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
DEBUG_printf("\n");
|
||||
}
|
||||
DEBUG_printf(" %02x", fun_data[i]);
|
||||
DEBUG_printf(" %02x", ((byte*)fun_data)[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
|
||||
#ifdef WRITE_CODE
|
||||
if (fp_write_code != NULL) {
|
||||
fwrite(fun_data, len, 1, fp_write_code);
|
||||
fflush(fp_write_code);
|
||||
}
|
||||
FILE *fp_write_code = fopen("out-code", "wb");
|
||||
fwrite(fun_data, fun_len, 1, fp_write_code);
|
||||
fclose(fp_write_code);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
|
||||
rc->kind = MP_CODE_INLINE_ASM;
|
||||
rc->scope_flags = 0;
|
||||
rc->n_pos_args = n_args;
|
||||
rc->u_inline_asm.fun = fun;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign inline asm code: fun=%p len=%u n_args=%d\n", fun, len, n_args);
|
||||
byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
DEBUG_printf("\n");
|
||||
}
|
||||
DEBUG_printf(" %02x", fun_data[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
|
||||
#ifdef WRITE_CODE
|
||||
if (fp_write_code != NULL) {
|
||||
fwrite(fun_data, len, 1, fp_write_code);
|
||||
fflush(fp_write_code);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
|
||||
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
|
||||
@@ -135,21 +121,28 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
// def_args must be MP_OBJ_NULL or a tuple
|
||||
assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
|
||||
|
||||
// TODO implement default kw args
|
||||
assert(def_kw_args == MP_OBJ_NULL);
|
||||
// def_kw_args must be MP_OBJ_NULL or a dict
|
||||
assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict));
|
||||
|
||||
// make the function, depending on the raw code kind
|
||||
mp_obj_t fun;
|
||||
switch (rc->kind) {
|
||||
case MP_CODE_BYTE:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, rc->u_byte.code);
|
||||
case MP_CODE_BYTECODE:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
|
||||
break;
|
||||
case MP_CODE_NATIVE:
|
||||
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
case MP_CODE_NATIVE_PY:
|
||||
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->u_native.fun_data);
|
||||
break;
|
||||
case MP_CODE_INLINE_ASM:
|
||||
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_inline_asm.fun);
|
||||
case MP_CODE_NATIVE_VIPER:
|
||||
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun_data, rc->u_native.type_sig);
|
||||
break;
|
||||
#endif
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
case MP_CODE_NATIVE_ASM:
|
||||
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun_data);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// raw code was never set (this should not happen)
|
||||
assert(0);
|
||||
@@ -164,8 +157,8 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
return fun;
|
||||
}
|
||||
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) {
|
||||
DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
|
||||
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
|
||||
// make function object
|
||||
mp_obj_t ffun;
|
||||
if (n_closed_over & 0x100) {
|
||||
|
||||
@@ -1,41 +1,62 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// These variables and functions glue the code emitters to the runtime.
|
||||
|
||||
typedef enum {
|
||||
MP_CODE_UNUSED,
|
||||
MP_CODE_RESERVED,
|
||||
MP_CODE_BYTE,
|
||||
MP_CODE_NATIVE,
|
||||
MP_CODE_INLINE_ASM,
|
||||
MP_CODE_BYTECODE,
|
||||
MP_CODE_NATIVE_PY,
|
||||
MP_CODE_NATIVE_VIPER,
|
||||
MP_CODE_NATIVE_ASM,
|
||||
} mp_raw_code_kind_t;
|
||||
|
||||
typedef struct _mp_code_t {
|
||||
mp_raw_code_kind_t kind : 3;
|
||||
uint scope_flags : 7;
|
||||
uint n_pos_args : 11;
|
||||
uint n_kwonly_args : 11;
|
||||
mp_uint_t scope_flags : 7;
|
||||
mp_uint_t n_pos_args : 11;
|
||||
mp_uint_t n_kwonly_args : 11;
|
||||
qstr *arg_names;
|
||||
union {
|
||||
struct {
|
||||
byte *code;
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
} u_byte;
|
||||
struct {
|
||||
mp_fun_t fun;
|
||||
void *fun_data;
|
||||
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
|
||||
} u_native;
|
||||
struct {
|
||||
void *fun;
|
||||
} u_inline_asm;
|
||||
};
|
||||
} mp_raw_code_t;
|
||||
|
||||
void mp_emit_glue_init(void);
|
||||
void mp_emit_glue_deinit(void);
|
||||
|
||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
|
||||
|
||||
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
|
||||
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
|
||||
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
|
||||
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags);
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
|
||||
|
||||
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);
|
||||
|
||||
@@ -1,11 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -63,7 +89,7 @@ STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pa
|
||||
emit->pass = pass;
|
||||
emit->success = true;
|
||||
emit->scope = scope;
|
||||
asm_thumb_start_pass(emit->as, pass);
|
||||
asm_thumb_start_pass(emit->as, pass == MP_PASS_EMIT ? ASM_THUMB_PASS_EMIT : ASM_THUMB_PASS_COMPUTE);
|
||||
asm_thumb_entry(emit->as, 0);
|
||||
}
|
||||
|
||||
@@ -71,9 +97,9 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
|
||||
asm_thumb_exit(emit->as);
|
||||
asm_thumb_end_pass(emit->as);
|
||||
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
void *f = asm_thumb_get_code(emit->as);
|
||||
mp_emit_glue_assign_inline_asm_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
|
||||
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
|
||||
}
|
||||
|
||||
return emit->success;
|
||||
@@ -141,7 +167,7 @@ STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
const char *reg_str = qstr_str(reg_qstr);
|
||||
for (uint i = 0; i < ARRAY_SIZE(reg_name_table); i++) {
|
||||
for (uint i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
|
||||
const reg_name_t *r = ®_name_table[i];
|
||||
if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
|
||||
if (r->reg > max_reg) {
|
||||
@@ -204,7 +230,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
|
||||
}
|
||||
}
|
||||
// only need to have the labels on the last pass
|
||||
if (emit->pass == PASS_3) {
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
emit_inline_thumb_error(emit, "label '%s' not defined\n", qstr_str(label_qstr));
|
||||
}
|
||||
return 0;
|
||||
@@ -260,7 +286,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
|
||||
asm_thumb_b_n(emit->as, label_num);
|
||||
} else if (op_str[0] == 'b' && op_len == 3) {
|
||||
uint cc = -1;
|
||||
for (uint i = 0; i < ARRAY_SIZE(cc_name_table); i++) {
|
||||
for (uint i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
|
||||
if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
|
||||
cc = cc_name_table[i].cc;
|
||||
}
|
||||
@@ -289,7 +315,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
|
||||
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
|
||||
uint reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
|
||||
asm_thumb_mov_reg_reg(emit->as, reg_dest, reg_src);
|
||||
} else if (strcmp(op_str, "and") == 0) {
|
||||
} else if (strcmp(op_str, "and_") == 0) {
|
||||
op_code = ASM_THUMB_FORMAT_4_AND;
|
||||
uint reg_dest, reg_src;
|
||||
op_format_4:
|
||||
@@ -297,7 +323,6 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
|
||||
reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
|
||||
asm_thumb_format_4(emit->as, op_code, reg_dest, reg_src);
|
||||
// TODO probably uses less ROM if these ops are in a lookup table
|
||||
} else if (strcmp(op_str, "and") == 0) { op_code = ASM_THUMB_FORMAT_4_AND; goto op_format_4;
|
||||
} else if (strcmp(op_str, "eor") == 0) { op_code = ASM_THUMB_FORMAT_4_EOR; goto op_format_4;
|
||||
} else if (strcmp(op_str, "lsl") == 0) { op_code = ASM_THUMB_FORMAT_4_LSL; goto op_format_4;
|
||||
} else if (strcmp(op_str, "lsr") == 0) { op_code = ASM_THUMB_FORMAT_4_LSR; goto op_format_4;
|
||||
|
||||
762
py/emitnative.c
762
py/emitnative.c
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -30,7 +56,7 @@ STATIC void emit_pass1_dummy(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
assert(pass == PASS_1);
|
||||
assert(pass == MP_PASS_SCOPE);
|
||||
emit->scope = scope;
|
||||
}
|
||||
|
||||
@@ -188,6 +214,10 @@ const emit_method_table_t emit_pass1_method_table = {
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
formatfloat.c - Ruutine for converting a single-precision floating
|
||||
@@ -49,7 +75,7 @@ int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char s
|
||||
|
||||
if (buf_size < 7) {
|
||||
// Smallest exp notion is -9e+99 which is 6 chars plus terminating
|
||||
// nulll.
|
||||
// null.
|
||||
|
||||
if (buf_size >= 2) {
|
||||
*s++ = '?';
|
||||
|
||||
@@ -1 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
int format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign);
|
||||
|
||||
270
py/gc.c
270
py/gc.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -7,7 +33,6 @@
|
||||
#include "misc.h"
|
||||
#include "gc.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -21,22 +46,26 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
// make this 1 to dump the heap each time it changes
|
||||
#define EXTENSIVE_HEAP_PROFILING (0)
|
||||
|
||||
#define WORDS_PER_BLOCK (4)
|
||||
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
|
||||
#define STACK_SIZE (64) // tunable; minimum is 1
|
||||
|
||||
STATIC byte *gc_alloc_table_start;
|
||||
STATIC machine_uint_t gc_alloc_table_byte_len;
|
||||
STATIC mp_uint_t gc_alloc_table_byte_len;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
STATIC byte *gc_finaliser_table_start;
|
||||
#endif
|
||||
STATIC machine_uint_t *gc_pool_start;
|
||||
STATIC machine_uint_t *gc_pool_end;
|
||||
STATIC mp_uint_t *gc_pool_start;
|
||||
STATIC mp_uint_t *gc_pool_end;
|
||||
|
||||
STATIC int gc_stack_overflow;
|
||||
STATIC machine_uint_t gc_stack[STACK_SIZE];
|
||||
STATIC machine_uint_t *gc_sp;
|
||||
STATIC machine_uint_t gc_lock_depth;
|
||||
STATIC mp_uint_t gc_stack[STACK_SIZE];
|
||||
STATIC mp_uint_t *gc_sp;
|
||||
STATIC mp_uint_t gc_lock_depth;
|
||||
STATIC mp_uint_t gc_last_free_atb_index;
|
||||
|
||||
// ATB = allocation table byte
|
||||
// 0b00 = FREE -- free block
|
||||
@@ -68,8 +97,8 @@ STATIC machine_uint_t gc_lock_depth;
|
||||
#define ATB_HEAD_TO_MARK(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_MARK_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
|
||||
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (machine_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (machine_uint_t)gc_pool_start))
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)gc_pool_start))
|
||||
#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -86,32 +115,35 @@ STATIC machine_uint_t gc_lock_depth;
|
||||
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
|
||||
void gc_init(void *start, void *end) {
|
||||
// align end pointer on block boundary
|
||||
end = (void*)((machine_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
|
||||
DEBUG_printf("Initializing GC heap: %p..%p = %ld bytes\n", start, end, end - start);
|
||||
end = (void*)((mp_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
|
||||
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start);
|
||||
|
||||
// calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
|
||||
// T = A + F + P
|
||||
// F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
|
||||
// P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
|
||||
// => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
|
||||
machine_uint_t total_byte_len = end - start;
|
||||
mp_uint_t total_byte_len = (byte*)end - (byte*)start;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
|
||||
#else
|
||||
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
|
||||
#endif
|
||||
|
||||
|
||||
gc_alloc_table_start = (byte*)start;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
machine_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB) / BLOCKS_PER_FTB;
|
||||
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
|
||||
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
|
||||
#endif
|
||||
|
||||
machine_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = end - gc_pool_block_len * BYTES_PER_BLOCK;
|
||||
gc_pool_end = end;
|
||||
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
|
||||
gc_pool_end = (mp_uint_t*)end;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
|
||||
#endif
|
||||
|
||||
// clear ATBs
|
||||
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
|
||||
@@ -128,6 +160,9 @@ void gc_init(void *start, void *end) {
|
||||
gc_pool_start[i] = 0;
|
||||
}
|
||||
|
||||
// set last free ATB index to start of heap
|
||||
gc_last_free_atb_index = 0;
|
||||
|
||||
// unlock the GC
|
||||
gc_lock_depth = 0;
|
||||
|
||||
@@ -147,16 +182,20 @@ void gc_unlock(void) {
|
||||
gc_lock_depth--;
|
||||
}
|
||||
|
||||
bool gc_is_locked(void) {
|
||||
return gc_lock_depth != 0;
|
||||
}
|
||||
|
||||
#define VERIFY_PTR(ptr) ( \
|
||||
(ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
|
||||
&& ptr >= (machine_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (machine_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
&& ptr >= (mp_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (mp_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
)
|
||||
|
||||
#define VERIFY_MARK_AND_PUSH(ptr) \
|
||||
do { \
|
||||
if (VERIFY_PTR(ptr)) { \
|
||||
machine_uint_t _block = BLOCK_FROM_PTR(ptr); \
|
||||
mp_uint_t _block = BLOCK_FROM_PTR(ptr); \
|
||||
if (ATB_GET_KIND(_block) == AT_HEAD) { \
|
||||
/* an unmarked head, mark it, and push it on gc stack */ \
|
||||
ATB_HEAD_TO_MARK(_block); \
|
||||
@@ -172,18 +211,18 @@ void gc_unlock(void) {
|
||||
STATIC void gc_drain_stack(void) {
|
||||
while (gc_sp > gc_stack) {
|
||||
// pop the next block off the stack
|
||||
machine_uint_t block = *--gc_sp;
|
||||
mp_uint_t block = *--gc_sp;
|
||||
|
||||
// work out number of consecutive blocks in the chain starting with this one
|
||||
machine_uint_t n_blocks = 0;
|
||||
mp_uint_t n_blocks = 0;
|
||||
do {
|
||||
n_blocks += 1;
|
||||
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
|
||||
|
||||
// check this block's children
|
||||
machine_uint_t *scan = (machine_uint_t*)PTR_FROM_BLOCK(block);
|
||||
for (machine_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
|
||||
machine_uint_t ptr2 = *scan;
|
||||
mp_uint_t *scan = (mp_uint_t*)PTR_FROM_BLOCK(block);
|
||||
for (mp_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
|
||||
mp_uint_t ptr2 = *scan;
|
||||
VERIFY_MARK_AND_PUSH(ptr2);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +234,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
|
||||
gc_sp = gc_stack;
|
||||
|
||||
// scan entire memory looking for blocks which have been marked but not their children
|
||||
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
// trace (again) if mark bit set
|
||||
if (ATB_GET_KIND(block) == AT_MARK) {
|
||||
*gc_sp++ = block;
|
||||
@@ -205,10 +244,17 @@ STATIC void gc_deal_with_stack_overflow(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
uint gc_collected;
|
||||
#endif
|
||||
|
||||
STATIC void gc_sweep(void) {
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
gc_collected = 0;
|
||||
#endif
|
||||
// free unmarked heads and their tails
|
||||
int free_tail = 0;
|
||||
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
switch (ATB_GET_KIND(block)) {
|
||||
case AT_HEAD:
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -228,10 +274,14 @@ STATIC void gc_sweep(void) {
|
||||
}
|
||||
#endif
|
||||
free_tail = 1;
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
gc_collected++;
|
||||
#endif
|
||||
// fall through to free the head
|
||||
|
||||
case AT_TAIL:
|
||||
if (free_tail) {
|
||||
DEBUG_printf("gc_sweep(%p)\n",PTR_FROM_BLOCK(block));
|
||||
ATB_ANY_TO_FREE(block);
|
||||
}
|
||||
break;
|
||||
@@ -250,9 +300,9 @@ void gc_collect_start(void) {
|
||||
gc_sp = gc_stack;
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, machine_uint_t len) {
|
||||
for (machine_uint_t i = 0; i < len; i++) {
|
||||
machine_uint_t ptr = (machine_uint_t)ptrs[i];
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len) {
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
VERIFY_MARK_AND_PUSH(ptr);
|
||||
gc_drain_stack();
|
||||
}
|
||||
@@ -261,18 +311,19 @@ void gc_collect_root(void **ptrs, machine_uint_t len) {
|
||||
void gc_collect_end(void) {
|
||||
gc_deal_with_stack_overflow();
|
||||
gc_sweep();
|
||||
gc_last_free_atb_index = 0;
|
||||
gc_unlock();
|
||||
}
|
||||
|
||||
void gc_info(gc_info_t *info) {
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(machine_uint_t);
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(mp_uint_t);
|
||||
info->used = 0;
|
||||
info->free = 0;
|
||||
info->num_1block = 0;
|
||||
info->num_2block = 0;
|
||||
info->max_block = 0;
|
||||
for (machine_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
machine_uint_t kind = ATB_GET_KIND(block);
|
||||
for (mp_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
mp_uint_t kind = ATB_GET_KIND(block);
|
||||
if (kind == AT_FREE || kind == AT_HEAD) {
|
||||
if (len == 1) {
|
||||
info->num_1block += 1;
|
||||
@@ -309,8 +360,8 @@ void gc_info(gc_info_t *info) {
|
||||
info->free *= BYTES_PER_BLOCK;
|
||||
}
|
||||
|
||||
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
|
||||
machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
|
||||
mp_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
|
||||
DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
|
||||
|
||||
// check if GC is locked
|
||||
@@ -323,15 +374,15 @@ void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
machine_uint_t i;
|
||||
machine_uint_t end_block;
|
||||
machine_uint_t start_block;
|
||||
machine_uint_t n_free = 0;
|
||||
mp_uint_t i;
|
||||
mp_uint_t end_block;
|
||||
mp_uint_t start_block;
|
||||
mp_uint_t n_free = 0;
|
||||
int collected = 0;
|
||||
for (;;) {
|
||||
|
||||
// look for a run of n_blocks available blocks
|
||||
for (i = 0; i < gc_alloc_table_byte_len; i++) {
|
||||
for (i = gc_last_free_atb_index; i < gc_alloc_table_byte_len; i++) {
|
||||
byte a = gc_alloc_table_start[i];
|
||||
if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
|
||||
if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
|
||||
@@ -354,24 +405,34 @@ found:
|
||||
end_block = i;
|
||||
start_block = i - n_free + 1;
|
||||
|
||||
// Set last free ATB index to block after last block we found, for start of
|
||||
// next scan. To reduce fragmentation, we only do this if we were looking
|
||||
// for a single free block, which guarantees that there are no free blocks
|
||||
// before this one. Also, whenever we free or shink a block we must check
|
||||
// if this index needs adjusting (see gc_realloc and gc_free).
|
||||
if (n_free == 1) {
|
||||
gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
// mark first block as used head
|
||||
ATB_FREE_TO_HEAD(start_block);
|
||||
|
||||
// mark rest of blocks as used tail
|
||||
// TODO for a run of many blocks can make this more efficient
|
||||
for (machine_uint_t bl = start_block + 1; bl <= end_block; bl++) {
|
||||
for (mp_uint_t bl = start_block + 1; bl <= end_block; bl++) {
|
||||
ATB_FREE_TO_TAIL(bl);
|
||||
}
|
||||
|
||||
// get pointer to first block
|
||||
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
|
||||
DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks
|
||||
// This is needed because the blocks may have previously held pointers
|
||||
// to the heap and will not be set to something else if the caller
|
||||
// doesn't actually use the entire block. As such they will continue
|
||||
// to point to the heap and may prevent other blocks from being reclaimed.
|
||||
memset(ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
|
||||
memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
if (has_finaliser) {
|
||||
@@ -382,15 +443,19 @@ found:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ret_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
void *gc_alloc(machine_uint_t n_bytes) {
|
||||
void *gc_alloc(mp_uint_t n_bytes) {
|
||||
return _gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
void *gc_alloc_with_finaliser(machine_uint_t n_bytes) {
|
||||
void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
|
||||
return _gc_alloc(n_bytes, true);
|
||||
}
|
||||
*/
|
||||
@@ -402,28 +467,38 @@ void gc_free(void *ptr_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
DEBUG_printf("gc_free(%p)\n", ptr);
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
// set the last_free pointer to this block if it's earlier in the heap
|
||||
if (block / BLOCKS_PER_ATB < gc_last_free_atb_index) {
|
||||
gc_last_free_atb_index = block / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
// free head and all of its tail blocks
|
||||
do {
|
||||
ATB_ANY_TO_FREE(block);
|
||||
block += 1;
|
||||
} while (ATB_GET_KIND(block) == AT_TAIL);
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
machine_uint_t gc_nbytes(void *ptr_in) {
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t gc_nbytes(void *ptr_in) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
// work out number of consecutive blocks in the chain starting with this on
|
||||
machine_uint_t n_blocks = 0;
|
||||
mp_uint_t n_blocks = 0;
|
||||
do {
|
||||
n_blocks += 1;
|
||||
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
|
||||
@@ -437,8 +512,8 @@ machine_uint_t gc_nbytes(void *ptr_in) {
|
||||
|
||||
#if 0
|
||||
// old, simple realloc that didn't expand memory in place
|
||||
void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
machine_uint_t n_existing = gc_nbytes(ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
|
||||
mp_uint_t n_existing = gc_nbytes(ptr);
|
||||
if (n_bytes <= n_existing) {
|
||||
return ptr;
|
||||
} else {
|
||||
@@ -447,7 +522,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
has_finaliser = false;
|
||||
} else {
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
has_finaliser = FTB_GET(BLOCK_FROM_PTR((machine_uint_t)ptr));
|
||||
has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));
|
||||
#else
|
||||
has_finaliser = false;
|
||||
#endif
|
||||
@@ -464,7 +539,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
|
||||
#else // Alternative gc_realloc impl
|
||||
|
||||
void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
if (gc_lock_depth > 0) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -474,7 +549,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
return gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
// sanity check the ptr
|
||||
if (!VERIFY_PTR(ptr)) {
|
||||
@@ -482,7 +557,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// get first block
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
|
||||
// sanity check the ptr is pointing to the head of a block
|
||||
if (ATB_GET_KIND(block) != AT_HEAD) {
|
||||
@@ -490,14 +565,14 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// compute number of new blocks that are requested
|
||||
machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
||||
mp_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
||||
|
||||
// get the number of consecutive tail blocks and
|
||||
// the number of free blocks after last tail block
|
||||
// stop if we reach (or are at) end of heap
|
||||
machine_uint_t n_free = 0;
|
||||
machine_uint_t n_blocks = 1; // counting HEAD block
|
||||
machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
mp_uint_t n_free = 0;
|
||||
mp_uint_t n_blocks = 1; // counting HEAD block
|
||||
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
while (block + n_blocks + n_free < max_block) {
|
||||
if (n_blocks + n_free >= new_blocks) {
|
||||
// stop as soon as we find enough blocks for n_bytes
|
||||
@@ -520,22 +595,36 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
// check if we can shrink the allocated area
|
||||
if (new_blocks < n_blocks) {
|
||||
// free unneeded tail blocks
|
||||
for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
|
||||
for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
|
||||
ATB_ANY_TO_FREE(bl);
|
||||
}
|
||||
|
||||
// set the last_free pointer to end of this block if it's earlier in the heap
|
||||
if ((block + new_blocks) / BLOCKS_PER_ATB < gc_last_free_atb_index) {
|
||||
gc_last_free_atb_index = (block + new_blocks) / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ptr_in;
|
||||
}
|
||||
|
||||
// check if we can expand in place
|
||||
if (new_blocks <= n_blocks + n_free) {
|
||||
// mark few more blocks as used tail
|
||||
for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
|
||||
for (mp_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
|
||||
assert(ATB_GET_KIND(bl) == AT_FREE);
|
||||
ATB_FREE_TO_TAIL(bl);
|
||||
}
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
|
||||
memset(ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
|
||||
memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ptr_in;
|
||||
}
|
||||
@@ -554,7 +643,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_printf("gc_realloc: allocating new block\n");
|
||||
DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out);
|
||||
memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
|
||||
gc_free(ptr_in);
|
||||
return ptr_out;
|
||||
@@ -570,9 +659,34 @@ void gc_dump_info() {
|
||||
}
|
||||
|
||||
void gc_dump_alloc_table(void) {
|
||||
static const mp_uint_t DUMP_BYTES_PER_LINE = 64;
|
||||
#if !EXTENSIVE_HEAP_PROFILING
|
||||
// When comparing heap output we don't want to print the starting
|
||||
// pointer of the heap because it changes from run to run.
|
||||
printf("GC memory layout; from %p:", gc_pool_start);
|
||||
for (machine_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % 64 == 0) {
|
||||
#endif
|
||||
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % DUMP_BYTES_PER_LINE == 0) {
|
||||
// a new line of blocks
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
{
|
||||
// check if this line contains only free blocks
|
||||
bool only_free_blocks = true;
|
||||
for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) {
|
||||
if (ATB_GET_KIND(bl2) != AT_FREE) {
|
||||
|
||||
only_free_blocks = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (only_free_blocks) {
|
||||
// line contains only free blocks, so skip printing it
|
||||
bl += DUMP_BYTES_PER_LINE - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// print header for new line of blocks
|
||||
printf("\n%04x: ", (uint)bl);
|
||||
}
|
||||
int c = ' ';
|
||||
@@ -581,12 +695,12 @@ void gc_dump_alloc_table(void) {
|
||||
case AT_HEAD: c = 'h'; break;
|
||||
/* this prints the uPy object type of the head block
|
||||
case AT_HEAD: {
|
||||
machine_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (machine_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_float) { c = 'F'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_float) { c = 'F'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
else { c = 'h'; }
|
||||
break;
|
||||
}
|
||||
@@ -601,23 +715,23 @@ void gc_dump_alloc_table(void) {
|
||||
|
||||
#if DEBUG_PRINT
|
||||
void gc_test(void) {
|
||||
machine_uint_t len = 500;
|
||||
machine_uint_t *heap = malloc(len);
|
||||
gc_init(heap, heap + len / sizeof(machine_uint_t));
|
||||
mp_uint_t len = 500;
|
||||
mp_uint_t *heap = malloc(len);
|
||||
gc_init(heap, heap + len / sizeof(mp_uint_t));
|
||||
void *ptrs[100];
|
||||
{
|
||||
machine_uint_t **p = gc_alloc(16, false);
|
||||
mp_uint_t **p = gc_alloc(16, false);
|
||||
p[0] = gc_alloc(64, false);
|
||||
p[1] = gc_alloc(1, false);
|
||||
p[2] = gc_alloc(1, false);
|
||||
p[3] = gc_alloc(1, false);
|
||||
machine_uint_t ***p2 = gc_alloc(16, false);
|
||||
mp_uint_t ***p2 = gc_alloc(16, false);
|
||||
p2[0] = p;
|
||||
p2[1] = p;
|
||||
ptrs[0] = p2;
|
||||
}
|
||||
for (int i = 0; i < 25; i+=2) {
|
||||
machine_uint_t *p = gc_alloc(i, false);
|
||||
mp_uint_t *p = gc_alloc(i, false);
|
||||
printf("p=%p\n", p);
|
||||
if (i & 3) {
|
||||
//ptrs[i] = p;
|
||||
|
||||
47
py/gc.h
47
py/gc.h
@@ -1,28 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
void gc_init(void *start, void *end);
|
||||
|
||||
// These lock/unlock functions can be nested.
|
||||
// They can be used to prevent the GC from allocating/freeing.
|
||||
void gc_lock(void);
|
||||
void gc_unlock(void);
|
||||
bool gc_is_locked(void);
|
||||
|
||||
// A given port must implement gc_collect by using the other collect functions.
|
||||
void gc_collect(void);
|
||||
void gc_collect_start(void);
|
||||
void gc_collect_root(void **ptrs, machine_uint_t len);
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len);
|
||||
void gc_collect_end(void);
|
||||
|
||||
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser);
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser);
|
||||
void gc_free(void *ptr);
|
||||
machine_uint_t gc_nbytes(void *ptr);
|
||||
void *gc_realloc(void *ptr, machine_uint_t n_bytes);
|
||||
mp_uint_t gc_nbytes(void *ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes);
|
||||
|
||||
typedef struct _gc_info_t {
|
||||
machine_uint_t total;
|
||||
machine_uint_t used;
|
||||
machine_uint_t free;
|
||||
machine_uint_t num_1block;
|
||||
machine_uint_t num_2block;
|
||||
machine_uint_t max_block;
|
||||
mp_uint_t total;
|
||||
mp_uint_t used;
|
||||
mp_uint_t free;
|
||||
mp_uint_t num_1block;
|
||||
mp_uint_t num_2block;
|
||||
mp_uint_t max_block;
|
||||
} gc_info_t;
|
||||
|
||||
void gc_info(gc_info_t *info);
|
||||
|
||||
26
py/grammar.h
26
py/grammar.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// rules for writing rules:
|
||||
// - zero_or_more is implemented using opt_rule around a one_or_more rule
|
||||
// - don't put opt_rule in arguments of or rule; instead, wrap the call to this or rule in opt_rule
|
||||
|
||||
195
py/lexer.c
195
py/lexer.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* lexer.c -- simple tokeniser for Python implementation
|
||||
*/
|
||||
|
||||
@@ -6,8 +32,8 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
@@ -19,28 +45,30 @@
|
||||
struct _mp_lexer_t {
|
||||
qstr source_name; // name of source
|
||||
void *stream_data; // data for stream
|
||||
mp_lexer_stream_next_char_t stream_next_char; // stream callback to get next char
|
||||
mp_lexer_stream_next_byte_t stream_next_byte; // stream callback to get next byte
|
||||
mp_lexer_stream_close_t stream_close; // stream callback to free
|
||||
|
||||
unichar chr0, chr1, chr2; // current cached characters from source
|
||||
|
||||
uint line; // source line
|
||||
uint column; // source column
|
||||
mp_uint_t line; // source line
|
||||
mp_uint_t column; // source column
|
||||
|
||||
int emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
|
||||
int nested_bracket_level; // >0 when there are nested brackets over multiple lines
|
||||
mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
|
||||
mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines
|
||||
|
||||
uint alloc_indent_level;
|
||||
uint num_indent_level;
|
||||
mp_uint_t alloc_indent_level;
|
||||
mp_uint_t num_indent_level;
|
||||
uint16_t *indent_level;
|
||||
|
||||
vstr_t vstr;
|
||||
mp_token_t tok_cur;
|
||||
};
|
||||
|
||||
mp_uint_t mp_optimise_value;
|
||||
|
||||
// TODO replace with a call to a standard function
|
||||
bool str_strn_equal(const char *str, const char *strn, int len) {
|
||||
uint i = 0;
|
||||
bool str_strn_equal(const char *str, const char *strn, mp_uint_t len) {
|
||||
mp_uint_t i = 0;
|
||||
|
||||
while (i < len && *str == *strn) {
|
||||
++i;
|
||||
@@ -53,10 +81,10 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
|
||||
|
||||
#ifdef MICROPY_DEBUG_PRINTERS
|
||||
void mp_token_show(const mp_token_t *tok) {
|
||||
printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
|
||||
printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:" UINT_FMT, tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
|
||||
if (tok->str != NULL && tok->len > 0) {
|
||||
const char *i = tok->str;
|
||||
const char *j = i + tok->len;
|
||||
const byte *i = (const byte *)tok->str;
|
||||
const byte *j = (const byte *)i + tok->len;
|
||||
printf(" ");
|
||||
while (i < j) {
|
||||
unichar c = utf8_get_char(i);
|
||||
@@ -75,7 +103,7 @@ void mp_token_show(const mp_token_t *tok) {
|
||||
#define CUR_CHAR(lex) ((lex)->chr0)
|
||||
|
||||
STATIC bool is_end(mp_lexer_t *lex) {
|
||||
return lex->chr0 == MP_LEXER_CHAR_EOF;
|
||||
return lex->chr0 == MP_LEXER_EOF;
|
||||
}
|
||||
|
||||
STATIC bool is_physical_newline(mp_lexer_t *lex) {
|
||||
@@ -143,11 +171,11 @@ STATIC bool is_tail_of_identifier(mp_lexer_t *lex) {
|
||||
}
|
||||
|
||||
STATIC void next_char(mp_lexer_t *lex) {
|
||||
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
int advance = 1;
|
||||
mp_uint_t advance = 1;
|
||||
|
||||
if (lex->chr0 == '\n') {
|
||||
// LF is a new line
|
||||
@@ -172,25 +200,26 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
for (; advance > 0; advance--) {
|
||||
lex->chr0 = lex->chr1;
|
||||
lex->chr1 = lex->chr2;
|
||||
lex->chr2 = lex->stream_next_char(lex->stream_data);
|
||||
if (lex->chr2 == MP_LEXER_CHAR_EOF) {
|
||||
lex->chr2 = lex->stream_next_byte(lex->stream_data);
|
||||
if (lex->chr2 == MP_LEXER_EOF) {
|
||||
// EOF
|
||||
if (lex->chr1 != MP_LEXER_CHAR_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
if (lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
lex->chr2 = '\n'; // insert newline at end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void indent_push(mp_lexer_t *lex, uint indent) {
|
||||
void indent_push(mp_lexer_t *lex, mp_uint_t indent) {
|
||||
if (lex->num_indent_level >= lex->alloc_indent_level) {
|
||||
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level * 2);
|
||||
lex->alloc_indent_level *= 2;
|
||||
// TODO use m_renew_maybe and somehow indicate an error if it fails... probably by using MP_TOKEN_MEMORY_ERROR
|
||||
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC);
|
||||
lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC;
|
||||
}
|
||||
lex->indent_level[lex->num_indent_level++] = indent;
|
||||
}
|
||||
|
||||
uint indent_top(mp_lexer_t *lex) {
|
||||
mp_uint_t indent_top(mp_lexer_t *lex) {
|
||||
return lex->indent_level[lex->num_indent_level - 1];
|
||||
}
|
||||
|
||||
@@ -276,12 +305,12 @@ STATIC const char *tok_kw[] = {
|
||||
"while",
|
||||
"with",
|
||||
"yield",
|
||||
NULL,
|
||||
"__debug__",
|
||||
};
|
||||
|
||||
STATIC int hex_digit(unichar c) {
|
||||
STATIC mp_uint_t hex_digit(unichar c) {
|
||||
// c is assumed to be hex digit
|
||||
int n = c - '0';
|
||||
mp_uint_t n = c - '0';
|
||||
if (n > 9) {
|
||||
n &= ~('a' - 'A');
|
||||
n -= ('A' - ('9' + 1));
|
||||
@@ -291,8 +320,9 @@ STATIC int hex_digit(unichar c) {
|
||||
|
||||
// This is called with CUR_CHAR() before first hex digit, and should return with
|
||||
// it pointing to last hex digit
|
||||
STATIC bool get_hex(mp_lexer_t *lex, int num_digits, uint *result) {
|
||||
uint num = 0;
|
||||
// num_digits must be greater than zero
|
||||
STATIC bool get_hex(mp_lexer_t *lex, mp_uint_t num_digits, mp_uint_t *result) {
|
||||
mp_uint_t num = 0;
|
||||
while (num_digits-- != 0) {
|
||||
next_char(lex);
|
||||
unichar c = CUR_CHAR(lex);
|
||||
@@ -365,7 +395,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
} else if (had_physical_newline && lex->nested_bracket_level == 0) {
|
||||
tok->kind = MP_TOKEN_NEWLINE;
|
||||
|
||||
uint num_spaces = lex->column - 1;
|
||||
mp_uint_t num_spaces = lex->column - 1;
|
||||
lex->emit_dent = 0;
|
||||
if (num_spaces == indent_top(lex)) {
|
||||
} else if (num_spaces > indent_top(lex)) {
|
||||
@@ -434,7 +464,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
next_char(lex);
|
||||
|
||||
// work out if it's a single or triple quoted literal
|
||||
int num_quotes;
|
||||
mp_uint_t num_quotes;
|
||||
if (is_char_and(lex, quote_char, quote_char)) {
|
||||
// triple quotes
|
||||
next_char(lex);
|
||||
@@ -446,7 +476,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
}
|
||||
|
||||
// parse the literal
|
||||
int n_closing = 0;
|
||||
mp_uint_t n_closing = 0;
|
||||
while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) {
|
||||
if (is_char(lex, quote_char)) {
|
||||
n_closing += 1;
|
||||
@@ -461,8 +491,8 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
vstr_add_char(&lex->vstr, '\\');
|
||||
} else {
|
||||
switch (c) {
|
||||
case MP_LEXER_CHAR_EOF: break; // TODO a proper error message?
|
||||
case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it
|
||||
case MP_LEXER_EOF: break; // TODO a proper error message?
|
||||
case '\n': c = MP_LEXER_EOF; break; // TODO check this works correctly (we are supposed to ignore it
|
||||
case '\\': break;
|
||||
case '\'': break;
|
||||
case '"': break;
|
||||
@@ -473,24 +503,37 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
case 'v': c = 0x0b; break;
|
||||
case 'f': c = 0x0c; break;
|
||||
case 'r': c = 0x0d; break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (is_bytes) {
|
||||
// b'\u1234' == b'\\u1234'
|
||||
vstr_add_char(&lex->vstr, '\\');
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through.
|
||||
case 'x':
|
||||
{
|
||||
uint num = 0;
|
||||
if (!get_hex(lex, 2, &num)) {
|
||||
mp_uint_t num = 0;
|
||||
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
|
||||
// TODO error message
|
||||
assert(0);
|
||||
}
|
||||
c = num;
|
||||
break;
|
||||
}
|
||||
case 'N': break; // TODO \N{name} only in strings
|
||||
case 'u': break; // TODO \uxxxx only in strings
|
||||
case 'U': break; // TODO \Uxxxxxxxx only in strings
|
||||
case 'N':
|
||||
// Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the
|
||||
// entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly
|
||||
// 3MB of text; even gzip-compressed and with minimal structure, it'll take
|
||||
// roughly half a meg of storage. This form of Unicode escape may be added
|
||||
// later on, but it's definitely not a priority right now. -- CJA 20140607
|
||||
assert(!"Unicode name escapes not supported");
|
||||
break;
|
||||
default:
|
||||
if (c >= '0' && c <= '7') {
|
||||
// Octal sequence, 1-3 chars
|
||||
int digits = 3;
|
||||
int num = c - '0';
|
||||
mp_uint_t digits = 3;
|
||||
mp_uint_t num = c - '0';
|
||||
while (is_following_odigit(lex) && --digits != 0) {
|
||||
next_char(lex);
|
||||
num = num * 8 + (CUR_CHAR(lex) - '0');
|
||||
@@ -503,11 +546,19 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c != MP_LEXER_CHAR_EOF) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
if (c != MP_LEXER_EOF) {
|
||||
if (c < 0x110000 && !is_bytes) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
} else if (c < 0x100 && is_bytes) {
|
||||
vstr_add_byte(&lex->vstr, c);
|
||||
} else {
|
||||
assert(!"TODO: Throw an error, invalid escape code probably");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
|
||||
// Add the "character" as a byte so that we remain 8-bit clean.
|
||||
// This way, strings are parsed correctly whether or not they contain utf-8 chars.
|
||||
vstr_add_byte(&lex->vstr, CUR_CHAR(lex));
|
||||
}
|
||||
}
|
||||
next_char(lex);
|
||||
@@ -579,7 +630,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
// search for encoded delimiter or operator
|
||||
|
||||
const char *t = tok_enc;
|
||||
uint tok_enc_index = 0;
|
||||
mp_uint_t tok_enc_index = 0;
|
||||
for (; *t != 0 && !is_char(lex, *t); t += 1) {
|
||||
if (*t == 'e' || *t == 'c') {
|
||||
t += 1;
|
||||
@@ -601,7 +652,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
|
||||
// get the maximum characters for a valid token
|
||||
t += 1;
|
||||
uint t_index = tok_enc_index;
|
||||
mp_uint_t t_index = tok_enc_index;
|
||||
for (;;) {
|
||||
for (; *t == 'e'; t += 1) {
|
||||
t += 1;
|
||||
@@ -660,45 +711,71 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
|
||||
// check for keywords
|
||||
if (tok->kind == MP_TOKEN_NAME) {
|
||||
for (int i = 0; tok_kw[i] != NULL; i++) {
|
||||
// We check for __debug__ here and convert it to its value. This is so
|
||||
// the parser gives a syntax error on, eg, x.__debug__. Otherwise, we
|
||||
// need to check for this special token in many places in the compiler.
|
||||
// TODO improve speed of these string comparisons
|
||||
//for (mp_int_t i = 0; tok_kw[i] != NULL; i++) {
|
||||
for (mp_int_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
|
||||
if (str_strn_equal(tok_kw[i], tok->str, tok->len)) {
|
||||
tok->kind = MP_TOKEN_KW_FALSE + i;
|
||||
if (i == MP_ARRAY_SIZE(tok_kw) - 1) {
|
||||
// tok_kw[MP_ARRAY_SIZE(tok_kw) - 1] == "__debug__"
|
||||
tok->kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
|
||||
} else {
|
||||
tok->kind = MP_TOKEN_KW_FALSE + i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *lex = m_new(mp_lexer_t, 1);
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *lex = m_new_maybe(mp_lexer_t, 1);
|
||||
|
||||
// check for memory allocation error
|
||||
if (lex == NULL) {
|
||||
if (stream_close) {
|
||||
stream_close(stream_data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lex->source_name = src_name;
|
||||
lex->stream_data = stream_data;
|
||||
lex->stream_next_char = stream_next_char;
|
||||
lex->stream_next_byte = stream_next_byte;
|
||||
lex->stream_close = stream_close;
|
||||
lex->line = 1;
|
||||
lex->column = 1;
|
||||
lex->emit_dent = 0;
|
||||
lex->nested_bracket_level = 0;
|
||||
lex->alloc_indent_level = 16;
|
||||
lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT;
|
||||
lex->num_indent_level = 1;
|
||||
lex->indent_level = m_new(uint16_t, lex->alloc_indent_level);
|
||||
lex->indent_level[0] = 0;
|
||||
lex->indent_level = m_new_maybe(uint16_t, lex->alloc_indent_level);
|
||||
vstr_init(&lex->vstr, 32);
|
||||
|
||||
// check for memory allocation error
|
||||
if (lex->indent_level == NULL || vstr_had_error(&lex->vstr)) {
|
||||
mp_lexer_free(lex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// store sentinel for first indentation level
|
||||
lex->indent_level[0] = 0;
|
||||
|
||||
// preload characters
|
||||
lex->chr0 = stream_next_char(stream_data);
|
||||
lex->chr1 = stream_next_char(stream_data);
|
||||
lex->chr2 = stream_next_char(stream_data);
|
||||
lex->chr0 = stream_next_byte(stream_data);
|
||||
lex->chr1 = stream_next_byte(stream_data);
|
||||
lex->chr2 = stream_next_byte(stream_data);
|
||||
|
||||
// if input stream is 0, 1 or 2 characters long and doesn't end in a newline, then insert a newline at the end
|
||||
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
lex->chr0 = '\n';
|
||||
} else if (lex->chr1 == MP_LEXER_CHAR_EOF) {
|
||||
} else if (lex->chr1 == MP_LEXER_EOF) {
|
||||
if (lex->chr0 != '\n' && lex->chr0 != '\r') {
|
||||
lex->chr1 = '\n';
|
||||
}
|
||||
} else if (lex->chr2 == MP_LEXER_CHAR_EOF) {
|
||||
} else if (lex->chr2 == MP_LEXER_EOF) {
|
||||
if (lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
lex->chr2 = '\n';
|
||||
}
|
||||
|
||||
48
py/lexer.h
48
py/lexer.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* lexer.h -- simple tokeniser for Micro Python
|
||||
*
|
||||
* Uses (byte) length instead of null termination.
|
||||
@@ -105,27 +131,27 @@ typedef enum _mp_token_kind_t {
|
||||
} mp_token_kind_t;
|
||||
|
||||
typedef struct _mp_token_t {
|
||||
uint src_line; // source line
|
||||
uint src_column; // source column
|
||||
mp_uint_t src_line; // source line
|
||||
mp_uint_t src_column; // source column
|
||||
|
||||
mp_token_kind_t kind; // kind of token
|
||||
const char *str; // string of token (valid only while this token is current token)
|
||||
uint len; // (byte) length of string of token
|
||||
mp_uint_t len; // (byte) length of string of token
|
||||
} mp_token_t;
|
||||
|
||||
// the next-char function must return the next character in the stream
|
||||
// it must return MP_LEXER_CHAR_EOF if end of stream
|
||||
// it can be called again after returning MP_LEXER_CHAR_EOF, and in that case must return MP_LEXER_CHAR_EOF
|
||||
#define MP_LEXER_CHAR_EOF (-1)
|
||||
typedef unichar (*mp_lexer_stream_next_char_t)(void*);
|
||||
// the next-byte function must return the next byte in the stream
|
||||
// it must return MP_LEXER_EOF if end of stream
|
||||
// it can be called again after returning MP_LEXER_EOF, and in that case must return MP_LEXER_EOF
|
||||
#define MP_LEXER_EOF (-1)
|
||||
typedef mp_uint_t (*mp_lexer_stream_next_byte_t)(void*);
|
||||
typedef void (*mp_lexer_stream_close_t)(void*);
|
||||
|
||||
typedef struct _mp_lexer_t mp_lexer_t;
|
||||
|
||||
void mp_token_show(const mp_token_t *tok);
|
||||
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close);
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len);
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close);
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
|
||||
|
||||
void mp_lexer_free(mp_lexer_t *lex);
|
||||
qstr mp_lexer_source_name(mp_lexer_t *lex);
|
||||
@@ -150,3 +176,5 @@ typedef enum {
|
||||
|
||||
mp_import_stat_t mp_import_stat(const char *path);
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
|
||||
|
||||
extern mp_uint_t mp_optimise_value;
|
||||
|
||||
@@ -1,21 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
typedef struct _mp_lexer_str_buf_t {
|
||||
uint free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
const char *src_beg; // beginning of source
|
||||
const char *src_cur; // current location in source
|
||||
const char *src_end; // end (exclusive) of source
|
||||
} mp_lexer_str_buf_t;
|
||||
|
||||
STATIC unichar str_buf_next_char(mp_lexer_str_buf_t *sb) {
|
||||
STATIC mp_uint_t str_buf_next_byte(mp_lexer_str_buf_t *sb) {
|
||||
if (sb->src_cur < sb->src_end) {
|
||||
return *sb->src_cur++;
|
||||
} else {
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +51,11 @@ STATIC void str_buf_free(mp_lexer_str_buf_t *sb) {
|
||||
m_del_obj(mp_lexer_str_buf_t, sb);
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len) {
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) {
|
||||
mp_lexer_str_buf_t *sb = m_new_obj(mp_lexer_str_buf_t);
|
||||
sb->free_len = free_len;
|
||||
sb->src_beg = str;
|
||||
sb->src_cur = str;
|
||||
sb->src_end = str + len;
|
||||
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_char_t)str_buf_next_char, (mp_lexer_stream_close_t)str_buf_free);
|
||||
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_byte_t)str_buf_next_byte, (mp_lexer_stream_close_t)str_buf_free);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if MICROPY_ENABLE_LEXER_UNIX
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -15,20 +41,20 @@
|
||||
|
||||
typedef struct _mp_lexer_file_buf_t {
|
||||
int fd;
|
||||
char buf[20];
|
||||
uint len;
|
||||
uint pos;
|
||||
byte buf[20];
|
||||
mp_uint_t len;
|
||||
mp_uint_t pos;
|
||||
} mp_lexer_file_buf_t;
|
||||
|
||||
STATIC unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
|
||||
STATIC mp_uint_t file_buf_next_byte(mp_lexer_file_buf_t *fb) {
|
||||
if (fb->pos >= fb->len) {
|
||||
if (fb->len == 0) {
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
} else {
|
||||
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
|
||||
if (n <= 0) {
|
||||
fb->len = 0;
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
}
|
||||
fb->len = n;
|
||||
fb->pos = 0;
|
||||
@@ -52,7 +78,7 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
|
||||
fb->len = n;
|
||||
fb->pos = 0;
|
||||
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
|
||||
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_byte_t)file_buf_next_byte, (mp_lexer_stream_close_t)file_buf_close);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_LEXER_UNIX
|
||||
#endif // MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
|
||||
|
||||
void mp_import_set_directory(const char *dir);
|
||||
|
||||
@@ -27,7 +27,8 @@ def compute_hash(qstr):
|
||||
hash = 5381
|
||||
for char in qstr:
|
||||
hash = (hash * 33) ^ ord(char)
|
||||
return hash & 0xffff
|
||||
# Make sure that valid hash is never zero, zero means "hash not computed"
|
||||
return (hash & 0xffff) or 1
|
||||
|
||||
def do_work(infiles):
|
||||
# read the qstrs in from the input files
|
||||
|
||||
28
py/malloc.c
28
py/malloc.c
@@ -1,9 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
|
||||
32
py/map.c
32
py/map.c
@@ -1,8 +1,34 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -141,7 +167,7 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
|
||||
}
|
||||
}
|
||||
|
||||
machine_uint_t hash = mp_obj_hash(index);
|
||||
mp_uint_t hash = mp_obj_hash(index);
|
||||
uint pos = hash % map->alloc;
|
||||
uint start_pos = pos;
|
||||
mp_map_elem_t *avail_slot = NULL;
|
||||
@@ -244,7 +270,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
machine_uint_t hash = mp_obj_hash(index);
|
||||
mp_uint_t hash = mp_obj_hash(index);
|
||||
uint pos = hash % set->alloc;
|
||||
uint start_pos = pos;
|
||||
mp_obj_t *avail_slot = NULL;
|
||||
|
||||
59
py/misc.h
59
py/misc.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// a mini library of useful types and functions
|
||||
|
||||
#ifndef _INCLUDED_MINILIB_H
|
||||
@@ -24,6 +50,7 @@ typedef unsigned int uint;
|
||||
// TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element)
|
||||
|
||||
#define m_new(type, num) ((type*)(m_malloc(sizeof(type) * (num))))
|
||||
#define m_new_maybe(type, num) ((type*)(m_malloc_maybe(sizeof(type) * (num))))
|
||||
#define m_new0(type, num) ((type*)(m_malloc0(sizeof(type) * (num))))
|
||||
#define m_new_obj(type) (m_new(type, 1))
|
||||
#define m_new_obj_var(obj_type, var_type, var_num) ((obj_type*)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num)))
|
||||
@@ -55,20 +82,30 @@ int m_get_peak_bytes_allocated(void);
|
||||
/** array helpers ***********************************************/
|
||||
|
||||
// get the number of elements in a fixed-size array
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
// align ptr to the nearest multiple of "alignment"
|
||||
#define MP_ALIGN(ptr, alignment) (void*)(((mp_uint_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
|
||||
|
||||
/** unichar / UTF-8 *********************************************/
|
||||
|
||||
typedef int unichar; // TODO
|
||||
|
||||
unichar utf8_get_char(const char *s);
|
||||
char *utf8_next_char(const char *s);
|
||||
unichar utf8_get_char(const byte *s);
|
||||
const byte *utf8_next_char(const byte *s);
|
||||
|
||||
bool unichar_isspace(unichar c);
|
||||
bool unichar_isalpha(unichar c);
|
||||
bool unichar_isprint(unichar c);
|
||||
bool unichar_isdigit(unichar c);
|
||||
bool unichar_isxdigit(unichar c);
|
||||
bool unichar_isupper(unichar c);
|
||||
bool unichar_islower(unichar c);
|
||||
unichar unichar_tolower(unichar c);
|
||||
unichar unichar_toupper(unichar c);
|
||||
mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
|
||||
#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
|
||||
#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
|
||||
|
||||
/** variable string *********************************************/
|
||||
|
||||
@@ -130,4 +167,20 @@ void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap);
|
||||
// Debugging helpers
|
||||
int DEBUG_printf(const char *fmt, ...);
|
||||
|
||||
extern uint mp_verbose_flag;
|
||||
|
||||
// This is useful for unicode handling. Some CPU archs has
|
||||
// special instructions for efficient implentation of this
|
||||
// function (e.g. CLZ on ARM).
|
||||
// NOTE: this function is unused at the moment
|
||||
#ifndef count_lead_ones
|
||||
static inline uint count_lead_ones(byte val) {
|
||||
uint c = 0;
|
||||
for (byte mask = 0x80; val & mask; mask >>= 1) {
|
||||
c++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _INCLUDED_MINILIB_H
|
||||
|
||||
@@ -73,9 +73,9 @@ all: $(PROG)
|
||||
|
||||
$(PROG): $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
|
||||
$(Q)$(CC) $(COPT) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
|
||||
ifndef DEBUG
|
||||
$(Q)$(STRIP) $(PROG)
|
||||
$(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
|
||||
endif
|
||||
$(Q)$(SIZE) $(PROG)
|
||||
|
||||
@@ -97,4 +97,10 @@ print-cfg:
|
||||
$(ECHO) "OBJ = $(OBJ)"
|
||||
.PHONY: print-cfg
|
||||
|
||||
print-def:
|
||||
@$(ECHO) "The following defines are built into the $(CC) compiler"
|
||||
touch __empty__.c
|
||||
@$(CC) -E -Wp,-dM __empty__.c
|
||||
@$(RM) -f __empty__.c
|
||||
|
||||
-include $(OBJ:.o=.P)
|
||||
|
||||
@@ -1,9 +1,37 @@
|
||||
#include "misc.h"
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_array_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array },
|
||||
@@ -14,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_array_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_array_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -25,3 +53,5 @@ const mp_obj_module_t mp_module_array = {
|
||||
.name = MP_QSTR_array,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_array_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,17 +1,52 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
|
||||
|
||||
/// \module cmath - mathematical functions for complex numbers
|
||||
///
|
||||
/// The `cmath` module provides some basic mathematical funtions for
|
||||
/// working with complex numbers.
|
||||
|
||||
// These are defined in modmath.c
|
||||
/// \constant e - base of the natural logarithm
|
||||
extern const mp_obj_float_t mp_math_e_obj;
|
||||
/// \constant pi - the ratio of a circle's circumference to its diameter
|
||||
extern const mp_obj_float_t mp_math_pi_obj;
|
||||
|
||||
/// \function phase(z)
|
||||
/// Returns the phase of the number `z`, in the range (-pi, +pi].
|
||||
mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -19,6 +54,8 @@ mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase);
|
||||
|
||||
/// \function polar(z)
|
||||
/// Returns, as a tuple, the polar form of `z`.
|
||||
mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -30,6 +67,8 @@ mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar);
|
||||
|
||||
/// \function rect(r, phi)
|
||||
/// Returns the complex number with modulus `r` and phase `phi`.
|
||||
mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
|
||||
mp_float_t r = mp_obj_get_float(r_obj);
|
||||
mp_float_t phi = mp_obj_get_float(phi_obj);
|
||||
@@ -37,6 +76,8 @@ mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect);
|
||||
|
||||
/// \function exp(z)
|
||||
/// Return the exponential of `z`.
|
||||
mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -45,6 +86,8 @@ mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
|
||||
|
||||
/// \function log(z)
|
||||
/// Return the natural logarithm of `z`. The branch cut is along the negative real axis.
|
||||
// TODO can take second argument, being the base
|
||||
mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
@@ -53,6 +96,8 @@ mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
|
||||
|
||||
/// \function log10(z)
|
||||
/// Return the base-10 logarithm of `z`. The branch cut is along the negative real axis.
|
||||
mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -60,6 +105,8 @@ mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
|
||||
|
||||
/// \function sqrt(z)
|
||||
/// Return the square-root of `z`.
|
||||
mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -69,6 +116,8 @@ mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
|
||||
|
||||
/// \function cos(z)
|
||||
/// Return the cosine of `z`.
|
||||
mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -76,6 +125,8 @@ mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos);
|
||||
|
||||
/// \function sin(z)
|
||||
/// Return the sine of `z`.
|
||||
mp_obj_t mp_cmath_sin(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -116,8 +167,8 @@ STATIC const mp_obj_dict_t mp_module_cmath_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_cmath_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -128,4 +179,4 @@ const mp_obj_module_t mp_module_cmath = {
|
||||
.globals = (mp_obj_dict_t*)&mp_module_cmath_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH
|
||||
#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
|
||||
|
||||
@@ -1,10 +1,36 @@
|
||||
#include "misc.h"
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#if MICROPY_PY_COLLECTIONS
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_collections_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__collections) },
|
||||
@@ -16,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_collections_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_collections_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -28,4 +54,4 @@ const mp_obj_module_t mp_module_collections = {
|
||||
.globals = (mp_obj_dict_t*)&mp_module_collections_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#endif // MICROPY_PY_COLLECTIONS
|
||||
|
||||
116
py/modgc.c
Normal file
116
py/modgc.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "runtime.h"
|
||||
#include "objlist.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "gc.h"
|
||||
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
|
||||
/// \module gc - control the garbage collector
|
||||
|
||||
extern uint gc_collected;
|
||||
|
||||
/// \function collect()
|
||||
/// Run a garbage collection.
|
||||
STATIC mp_obj_t py_gc_collect(void) {
|
||||
gc_collect();
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
return MP_OBJ_NEW_SMALL_INT(gc_collected);
|
||||
#else
|
||||
return mp_const_none;
|
||||
#endif
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||
|
||||
/// \function disable()
|
||||
/// Disable the garbage collector.
|
||||
STATIC mp_obj_t gc_disable(void) {
|
||||
gc_lock();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||
|
||||
/// \function enable()
|
||||
/// Enable the garbage collector.
|
||||
STATIC mp_obj_t gc_enable(void) {
|
||||
gc_unlock();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
||||
|
||||
/// \function mem_free()
|
||||
/// Return the number of bytes of available heap RAM.
|
||||
STATIC mp_obj_t gc_mem_free(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT(info.free);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free);
|
||||
|
||||
/// \function mem_alloc()
|
||||
/// Return the number of bytes of heap RAM that are allocated.
|
||||
STATIC mp_obj_t gc_mem_alloc(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT(info.used);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_gc_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gc) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_gc_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_gc_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_gc = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_gc,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_gc_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
51
py/modio.c
51
py/modio.c
@@ -1,18 +1,55 @@
|
||||
#include "misc.h"
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_IO
|
||||
#if MICROPY_PY_IO
|
||||
|
||||
extern const mp_obj_type_t mp_type_fileio;
|
||||
extern const mp_obj_type_t mp_type_textio;
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_io_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_io) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__io) },
|
||||
// Note: mp_builtin_open_obj should be defined by port, it's not
|
||||
// part of the core.
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_stringio },
|
||||
#if MICROPY_PY_IO_FILEIO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_FileIO), (mp_obj_t)&mp_type_fileio },
|
||||
#endif
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_TextIOWrapper), (mp_obj_t)&mp_type_textio },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio },
|
||||
#if MICROPY_PY_IO_BYTESIO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_io_globals = {
|
||||
@@ -20,15 +57,15 @@ STATIC const mp_obj_dict_t mp_module_io_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_io_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_io = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_io,
|
||||
.name = MP_QSTR__io,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_io_globals,
|
||||
};
|
||||
|
||||
|
||||
93
py/modmath.c
93
py/modmath.c
@@ -1,12 +1,43 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_MATH
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
|
||||
|
||||
/// \module math - mathematical functions
|
||||
///
|
||||
/// The `math` module provides some basic mathematical funtions for
|
||||
/// working with floating-point numbers.
|
||||
|
||||
//TODO: Change macros to check for overflow and raise OverflowError or RangeError
|
||||
#define MATH_FUN_1(py_name, c_name) \
|
||||
@@ -22,50 +53,95 @@
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
|
||||
|
||||
#define MATH_FUN_1_TO_INT(py_name, c_name) \
|
||||
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((machine_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
|
||||
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((mp_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
|
||||
|
||||
// These are also used by cmath.c
|
||||
/// \constant e - base of the natural logarithm
|
||||
const mp_obj_float_t mp_math_e_obj = {{&mp_type_float}, M_E};
|
||||
/// \constant pi - the ratio of a circle's circumference to its diameter
|
||||
const mp_obj_float_t mp_math_pi_obj = {{&mp_type_float}, M_PI};
|
||||
|
||||
/// \function sqrt(x)
|
||||
/// Returns the square root of `x`.
|
||||
MATH_FUN_1(sqrt, sqrt)
|
||||
/// \function pow(x, y)
|
||||
/// Returns `x` to the power of `y`.
|
||||
MATH_FUN_2(pow, pow)
|
||||
/// \function exp(x)
|
||||
MATH_FUN_1(exp, exp)
|
||||
/// \function expm1(x)
|
||||
MATH_FUN_1(expm1, expm1)
|
||||
/// \function log(x)
|
||||
MATH_FUN_1(log, log)
|
||||
/// \function log2(x)
|
||||
MATH_FUN_1(log2, log2)
|
||||
/// \function log10(x)
|
||||
MATH_FUN_1(log10, log10)
|
||||
/// \function cosh(x)
|
||||
MATH_FUN_1(cosh, cosh)
|
||||
/// \function sinh(x)
|
||||
MATH_FUN_1(sinh, sinh)
|
||||
/// \function tanh(x)
|
||||
MATH_FUN_1(tanh, tanh)
|
||||
/// \function acosh(x)
|
||||
MATH_FUN_1(acosh, acosh)
|
||||
/// \function asinh(x)
|
||||
MATH_FUN_1(asinh, asinh)
|
||||
/// \function atanh(x)
|
||||
MATH_FUN_1(atanh, atanh)
|
||||
/// \function cos(x)
|
||||
MATH_FUN_1(cos, cos)
|
||||
/// \function sin(x)
|
||||
MATH_FUN_1(sin, sin)
|
||||
/// \function tan(x)
|
||||
MATH_FUN_1(tan, tan)
|
||||
/// \function acos(x)
|
||||
MATH_FUN_1(acos, acos)
|
||||
/// \function asin(x)
|
||||
MATH_FUN_1(asin, asin)
|
||||
/// \function atan(x)
|
||||
MATH_FUN_1(atan, atan)
|
||||
/// \function atan2(y, x)
|
||||
MATH_FUN_2(atan2, atan2)
|
||||
/// \function ceil(x)
|
||||
MATH_FUN_1_TO_INT(ceil, ceil)
|
||||
/// \function copysign(x, y)
|
||||
MATH_FUN_2(copysign, copysign)
|
||||
/// \function fabs(x)
|
||||
MATH_FUN_1(fabs, fabs)
|
||||
/// \function floor(x)
|
||||
MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
|
||||
/// \function fmod(x, y)
|
||||
MATH_FUN_2(fmod, fmod)
|
||||
/// \function isfinite(x)
|
||||
MATH_FUN_1_TO_BOOL(isfinite, isfinite)
|
||||
/// \function isinf(x)
|
||||
MATH_FUN_1_TO_BOOL(isinf, isinf)
|
||||
/// \function isnan(x)
|
||||
MATH_FUN_1_TO_BOOL(isnan, isnan)
|
||||
/// \function trunc(x)
|
||||
MATH_FUN_1_TO_INT(trunc, trunc)
|
||||
/// \function ldexp(x, exp)
|
||||
MATH_FUN_2(ldexp, ldexp)
|
||||
/// \function erf(x)
|
||||
/// Return the error function of `x`.
|
||||
MATH_FUN_1(erf, erf)
|
||||
/// \function erfc(x)
|
||||
/// Return the complementary error function of `x`.
|
||||
MATH_FUN_1(erfc, erfc)
|
||||
/// \function gamma(x)
|
||||
/// Return the gamma function of `x`.
|
||||
MATH_FUN_1(gamma, tgamma)
|
||||
/// \function lgamma(x)
|
||||
/// return the natural logarithm of the gamma function of `x`.
|
||||
MATH_FUN_1(lgamma, lgamma)
|
||||
//TODO: factorial, fsum
|
||||
|
||||
// Functions that return a tuple
|
||||
|
||||
/// \function frexp(x)
|
||||
/// Converts a floating-point number to fractional and integral components.
|
||||
mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
|
||||
int int_exponent = 0;
|
||||
mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);
|
||||
@@ -76,6 +152,7 @@ mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
|
||||
|
||||
/// \function modf(x)
|
||||
mp_obj_t mp_math_modf(mp_obj_t x_obj) {
|
||||
mp_float_t int_part = 0.0;
|
||||
mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
|
||||
@@ -87,11 +164,14 @@ mp_obj_t mp_math_modf(mp_obj_t x_obj) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);
|
||||
|
||||
// Angular conversions
|
||||
|
||||
/// \function radians(x)
|
||||
mp_obj_t mp_math_radians(mp_obj_t x_obj) {
|
||||
return mp_obj_new_float(mp_obj_get_float(x_obj) * M_PI / 180.0);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);
|
||||
|
||||
/// \function degrees(x)
|
||||
mp_obj_t mp_math_degrees(mp_obj_t x_obj) {
|
||||
return mp_obj_new_float(mp_obj_get_float(x_obj) * 180.0 / M_PI);
|
||||
}
|
||||
@@ -125,6 +205,7 @@ STATIC const mp_map_elem_t mp_module_math_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_copysign), (mp_obj_t)&mp_math_copysign_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_fabs), (mp_obj_t)&mp_math_fabs_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&mp_math_floor_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_fmod), (mp_obj_t)&mp_math_fmod_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_frexp), (mp_obj_t)&mp_math_frexp_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ldexp), (mp_obj_t)&mp_math_ldexp_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_modf), (mp_obj_t)&mp_math_modf_obj },
|
||||
@@ -145,8 +226,8 @@ STATIC const mp_obj_dict_t mp_module_math_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_math_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -157,4 +238,4 @@ const mp_obj_module_t mp_module_math = {
|
||||
.globals = (mp_obj_dict_t*)&mp_module_math_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_MATH
|
||||
#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
#include "misc.h"
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -9,15 +35,15 @@
|
||||
|
||||
#if MICROPY_MEM_STATS
|
||||
STATIC mp_obj_t mp_micropython_mem_total() {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_total_bytes_allocated());
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_micropython_mem_current() {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_current_bytes_allocated());
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_micropython_mem_peak() {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_peak_bytes_allocated());
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);
|
||||
@@ -25,6 +51,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
|
||||
#if MICROPY_MEM_STATS
|
||||
@@ -32,6 +62,9 @@ STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_current), (mp_obj_t)&mp_micropython_mem_current_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alloc_emergency_exception_buf), (mp_obj_t)&mp_alloc_emergency_exception_buf_obj },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_micropython_globals = {
|
||||
@@ -39,8 +72,8 @@ STATIC const mp_obj_dict_t mp_module_micropython_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_micropython_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
138
py/modstruct.c
138
py/modstruct.c
@@ -1,15 +1,59 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "binary.h"
|
||||
#include "parsenum.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_STRUCT
|
||||
#if MICROPY_PY_STRUCT
|
||||
|
||||
/*
|
||||
This module implements most of character typecodes from CPython, with
|
||||
some extensions:
|
||||
|
||||
O - (Pointer to) an arbitrary Python object. This is useful for callback
|
||||
data, etc. Note that you must keep reference to passed object in
|
||||
your Python application, otherwise it may be garbage-collected,
|
||||
and then when you get back this value from callback it may be
|
||||
invalid (and lead to crash).
|
||||
S - Pointer to a string (returned as a Python string). Note the
|
||||
difference from "Ns", - the latter says "in this place of structure
|
||||
is character data of up to N bytes length", while "S" means
|
||||
"in this place of a structure is a pointer to zero-terminated
|
||||
character data".
|
||||
*/
|
||||
|
||||
STATIC char get_fmt_type(const char **fmt) {
|
||||
char t = **fmt;
|
||||
@@ -30,20 +74,51 @@ STATIC char get_fmt_type(const char **fmt) {
|
||||
return t;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t get_fmt_num(const char **p) {
|
||||
const char *num = *p;
|
||||
uint len = 1;
|
||||
while (unichar_isdigit(*++num)) {
|
||||
len++;
|
||||
}
|
||||
mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10));
|
||||
*p = num;
|
||||
return val;
|
||||
}
|
||||
|
||||
STATIC uint calcsize_items(const char *fmt) {
|
||||
// TODO
|
||||
return strlen(fmt);
|
||||
uint cnt = 0;
|
||||
while (*fmt) {
|
||||
// TODO supports size spec only for "s"
|
||||
if (!unichar_isdigit(*fmt++)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
|
||||
const char *fmt = mp_obj_str_get_str(fmt_in);
|
||||
char fmt_type = get_fmt_type(&fmt);
|
||||
machine_uint_t size;
|
||||
mp_uint_t size;
|
||||
for (size = 0; *fmt; fmt++) {
|
||||
uint align;
|
||||
int sz = mp_binary_get_size(fmt_type, *fmt, &align);
|
||||
uint align = 1;
|
||||
mp_uint_t cnt = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
cnt = get_fmt_num(&fmt);
|
||||
}
|
||||
if (cnt > 1) {
|
||||
// TODO: count spec support only for string len
|
||||
assert(*fmt == 's');
|
||||
}
|
||||
|
||||
mp_uint_t sz;
|
||||
if (*fmt == 's') {
|
||||
sz = cnt;
|
||||
} else {
|
||||
sz = (mp_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
|
||||
}
|
||||
// TODO
|
||||
assert(sz != -1);
|
||||
assert(sz != (mp_uint_t)-1);
|
||||
// Apply alignment
|
||||
size = (size + align - 1) & ~(align - 1);
|
||||
size += sz;
|
||||
@@ -63,7 +138,22 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) {
|
||||
byte *p = bufinfo.buf;
|
||||
|
||||
for (uint i = 0; i < size; i++) {
|
||||
mp_obj_t item = mp_binary_get_val(fmt_type, *fmt++, &p);
|
||||
mp_uint_t sz = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
sz = get_fmt_num(&fmt);
|
||||
}
|
||||
if (sz > 1) {
|
||||
// TODO: size spec support only for string len
|
||||
assert(*fmt == 's');
|
||||
}
|
||||
mp_obj_t item;
|
||||
if (*fmt == 's') {
|
||||
item = mp_obj_new_bytes(p, sz);
|
||||
p += sz;
|
||||
fmt++;
|
||||
} else {
|
||||
item = mp_binary_get_val(fmt_type, *fmt++, &p);
|
||||
}
|
||||
res->items[i] = item;
|
||||
}
|
||||
return res;
|
||||
@@ -80,11 +170,33 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
|
||||
memset(p, 0, size);
|
||||
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
mp_binary_set_val(fmt_type, *fmt++, args[i], &p);
|
||||
mp_uint_t sz = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
sz = get_fmt_num(&fmt);
|
||||
}
|
||||
if (sz > 1) {
|
||||
// TODO: size spec support only for string len
|
||||
assert(*fmt == 's');
|
||||
}
|
||||
|
||||
if (*fmt == 's') {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[i], &bufinfo, MP_BUFFER_READ);
|
||||
mp_uint_t to_copy = sz;
|
||||
if (bufinfo.len < to_copy) {
|
||||
to_copy = bufinfo.len;
|
||||
}
|
||||
memcpy(p, bufinfo.buf, to_copy);
|
||||
memset(p + to_copy, 0, sz - to_copy);
|
||||
p += sz;
|
||||
fmt++;
|
||||
} else {
|
||||
mp_binary_set_val(fmt_type, *fmt++, args[i], &p);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, -1, struct_pack);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_struct_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_struct) },
|
||||
@@ -98,8 +210,8 @@ STATIC const mp_obj_dict_t mp_module_struct_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_struct_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
85
py/modsys.c
85
py/modsys.c
@@ -1,5 +1,33 @@
|
||||
#include "misc.h"
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -7,37 +35,76 @@
|
||||
#include "objlist.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
|
||||
/// \module sys - system specific functions
|
||||
|
||||
// These should be implemented by ports, specific types don't matter,
|
||||
// only addresses.
|
||||
struct _dummy_t;
|
||||
extern struct _dummy_t mp_sys_stdin_obj;
|
||||
extern struct _dummy_t mp_sys_stdout_obj;
|
||||
extern struct _dummy_t mp_sys_stderr_obj;
|
||||
extern struct _dummy_t mp_sys_exit_obj;
|
||||
|
||||
extern mp_obj_int_t mp_maxsize_obj;
|
||||
|
||||
// TODO document these properly, they aren't constants or functions...
|
||||
/// \constant path - a mutable list of directories to search for imported modules
|
||||
mp_obj_list_t mp_sys_path_obj;
|
||||
/// \constant argv - a mutable list of arguments this program started with
|
||||
mp_obj_list_t mp_sys_argv_obj;
|
||||
|
||||
/// \constant version - Python language version that this implementation conforms to, as a string
|
||||
STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
|
||||
|
||||
/// \constant version_info - Python language version that this implementation conforms to, as a tuple of ints
|
||||
#define I(n) MP_OBJ_NEW_SMALL_INT(n)
|
||||
// TODO: CPython is now at 5-element array, but save 2 els so far...
|
||||
STATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3), I(4), I(0)}};
|
||||
#undef I
|
||||
STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
|
||||
|
||||
#ifdef MICROPY_PY_SYS_PLATFORM
|
||||
/// \constant platform - the platform that Micro Python is running on
|
||||
STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_path), (mp_obj_t)&mp_sys_path_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_argv), (mp_obj_t)&mp_sys_argv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_version), (mp_obj_t)&version_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_version_info), (mp_obj_t)&mp_sys_version_info_obj },
|
||||
#ifdef MICROPY_PY_SYS_PLATFORM
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_platform), (mp_obj_t)&platform_obj },
|
||||
#endif
|
||||
/// \constant byteorder - the byte order of the system ("little" or "big")
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_byteorder), MP_OBJ_NEW_QSTR(MP_QSTR_little) },
|
||||
#else
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_byteorder), MP_OBJ_NEW_QSTR(MP_QSTR_big) },
|
||||
#endif
|
||||
#if MICROPY_PY_SYS_MAXSIZE
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
|
||||
// INT_MAX is not representable as small int, as we know that small int
|
||||
// takes one bit for tag. So, we have little choice but to provide this
|
||||
// value. Apps also should be careful to not try to compare sys.maxsize
|
||||
// with some number (which may not fit in available int size), but instead
|
||||
// count number of significant bits in sys.maxsize.
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_maxsize), MP_OBJ_NEW_SMALL_INT(INT_MAX >> 1) },
|
||||
#else
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_maxsize), (mp_obj_t)&mp_maxsize_obj },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MICROPY_MOD_SYS_STDFILES
|
||||
#if MICROPY_PY_SYS_EXIT
|
||||
// documented per-port
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_exit), (mp_obj_t)&mp_sys_exit_obj },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_STDFILES
|
||||
// documented per-port
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdin), (mp_obj_t)&mp_sys_stdin_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj },
|
||||
@@ -49,8 +116,8 @@ STATIC const mp_obj_dict_t mp_module_sys_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_sys_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
360
py/mpconfig.h
360
py/mpconfig.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This file contains default configuration settings for MicroPython.
|
||||
// You can override any of these options using mpconfigport.h file located
|
||||
// in a directory of your port.
|
||||
@@ -7,6 +33,60 @@
|
||||
// Any options not explicitly set in mpconfigport.h will get default
|
||||
// values below.
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Memory allocation policy */
|
||||
|
||||
// Initial amount for lexer indentation level
|
||||
#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT
|
||||
#define MICROPY_ALLOC_LEXER_INDENT_INIT (10)
|
||||
#endif
|
||||
|
||||
// Increment for lexer indentation level
|
||||
#ifndef MICROPY_ALLOC_LEXEL_INDENT_INC
|
||||
#define MICROPY_ALLOC_LEXEL_INDENT_INC (8)
|
||||
#endif
|
||||
|
||||
// Initial amount for parse rule stack
|
||||
#ifndef MICROPY_ALLOC_PARSE_RULE_INIT
|
||||
#define MICROPY_ALLOC_PARSE_RULE_INIT (64)
|
||||
#endif
|
||||
|
||||
// Increment for parse rule stack
|
||||
#ifndef MICROPY_ALLOC_PARSE_RULE_INC
|
||||
#define MICROPY_ALLOC_PARSE_RULE_INC (16)
|
||||
#endif
|
||||
|
||||
// Initial amount for parse result stack
|
||||
#ifndef MICROPY_ALLOC_PARSE_RESULT_INIT
|
||||
#define MICROPY_ALLOC_PARSE_RESULT_INIT (32)
|
||||
#endif
|
||||
|
||||
// Increment for parse result stack
|
||||
#ifndef MICROPY_ALLOC_PARSE_RESULT_INC
|
||||
#define MICROPY_ALLOC_PARSE_RESULT_INC (16)
|
||||
#endif
|
||||
|
||||
// Strings this length or less will be interned by the parser
|
||||
#ifndef MICROPY_ALLOC_PARSE_INTERN_STRING_LEN
|
||||
#define MICROPY_ALLOC_PARSE_INTERN_STRING_LEN (10)
|
||||
#endif
|
||||
|
||||
// Initial amount for ids in a scope
|
||||
#ifndef MICROPY_ALLOC_SCOPE_ID_INIT
|
||||
#define MICROPY_ALLOC_SCOPE_ID_INIT (4)
|
||||
#endif
|
||||
|
||||
// Increment for ids in a scope
|
||||
#ifndef MICROPY_ALLOC_SCOPE_ID_INC
|
||||
#define MICROPY_ALLOC_SCOPE_ID_INC (6)
|
||||
#endif
|
||||
|
||||
// Maximum length of a path in the filesystem
|
||||
// So we can allocate a buffer on the stack for path manipulation in import
|
||||
#ifndef MICROPY_ALLOC_PATH_MAX
|
||||
#define MICROPY_ALLOC_PATH_MAX (512)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Micro Python emitters */
|
||||
|
||||
@@ -31,6 +111,22 @@
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#endif
|
||||
|
||||
// Whether to emit ARM native code
|
||||
#ifndef MICROPY_EMIT_ARM
|
||||
#define MICROPY_EMIT_ARM (0)
|
||||
#endif
|
||||
|
||||
// Convenience definition for whether any native emitter is enabled
|
||||
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Compiler configuration */
|
||||
|
||||
// Whether to enable constant optimisation; id = const(value)
|
||||
#ifndef MICROPY_COMP_CONST
|
||||
#define MICROPY_COMP_CONST (1)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Internal debugging stuff */
|
||||
|
||||
@@ -41,14 +137,23 @@
|
||||
|
||||
// Whether to build functions that print debugging info:
|
||||
// mp_token_show
|
||||
// mp_byte_code_print
|
||||
// mp_bytecode_print
|
||||
// mp_parse_node_print
|
||||
#ifndef MICROPY_DEBUG_PRINTERS
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Fine control over Python features */
|
||||
/* Optimisations */
|
||||
|
||||
// Whether to use computed gotos in the VM, or a switch
|
||||
// Computed gotos are roughly 10% faster, and increase VM code size by a little
|
||||
#ifndef MICROPY_OPT_COMPUTED_GOTO
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python internal features */
|
||||
|
||||
// Whether to include the garbage collector
|
||||
#ifndef MICROPY_ENABLE_GC
|
||||
@@ -60,14 +165,30 @@
|
||||
#define MICROPY_ENABLE_GC_FINALISER (0)
|
||||
#endif
|
||||
|
||||
// Whether to check C stack usage. C stack used for calling Python functions,
|
||||
// etc. Not checking means segfault on overflow.
|
||||
#ifndef MICROPY_STACK_CHECK
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#endif
|
||||
|
||||
// Whether to have an emergency exception buffer
|
||||
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
# ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
|
||||
# define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) // 0 - implies dynamic allocation
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Whether to include REPL helper function
|
||||
#ifndef MICROPY_ENABLE_REPL_HELPERS
|
||||
#define MICROPY_ENABLE_REPL_HELPERS (0)
|
||||
#ifndef MICROPY_HELPER_REPL
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#endif
|
||||
|
||||
// Whether to include lexer helper function for unix
|
||||
#ifndef MICROPY_ENABLE_LEXER_UNIX
|
||||
#define MICROPY_ENABLE_LEXER_UNIX (0)
|
||||
#ifndef MICROPY_HELPER_LEXER_UNIX
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#endif
|
||||
|
||||
// Long int implementation
|
||||
@@ -115,60 +236,19 @@ typedef long long mp_longint_impl_t;
|
||||
#endif
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
#define MICROPY_ENABLE_FLOAT (1)
|
||||
#define MICROPY_PY_BUILTINS_FLOAT (1)
|
||||
#define MICROPY_FLOAT_C_FUN(fun) fun##f
|
||||
typedef float mp_float_t;
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
#define MICROPY_ENABLE_FLOAT (1)
|
||||
#define MICROPY_PY_BUILTINS_FLOAT (1)
|
||||
#define MICROPY_FLOAT_C_FUN(fun) fun
|
||||
typedef double mp_float_t;
|
||||
#else
|
||||
#define MICROPY_ENABLE_FLOAT (0)
|
||||
#define MICROPY_PY_BUILTINS_FLOAT (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "collections" module
|
||||
#ifndef MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#define MICROPY_ENABLE_MOD_COLLECTIONS (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "math" module
|
||||
#ifndef MICROPY_ENABLE_MOD_MATH
|
||||
#define MICROPY_ENABLE_MOD_MATH (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "cmath" module
|
||||
#ifndef MICROPY_ENABLE_MOD_CMATH
|
||||
#define MICROPY_ENABLE_MOD_CMATH (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io" module
|
||||
#ifndef MICROPY_ENABLE_MOD_IO
|
||||
#define MICROPY_ENABLE_MOD_IO (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "struct" module
|
||||
#ifndef MICROPY_ENABLE_MOD_STRUCT
|
||||
#define MICROPY_ENABLE_MOD_STRUCT (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys" module
|
||||
#ifndef MICROPY_ENABLE_MOD_SYS
|
||||
#define MICROPY_ENABLE_MOD_SYS (1)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_MOD_SYS_STDFILES
|
||||
#define MICROPY_MOD_SYS_STDFILES (0)
|
||||
#endif
|
||||
|
||||
// Whether to support slice object and correspondingly
|
||||
// slice subscript operators
|
||||
#ifndef MICROPY_ENABLE_SLICE
|
||||
#define MICROPY_ENABLE_SLICE (1)
|
||||
#endif
|
||||
|
||||
// Whether to support the property object
|
||||
#ifndef MICROPY_ENABLE_PROPERTY
|
||||
#define MICROPY_ENABLE_PROPERTY (1)
|
||||
#ifndef MICROPY_PY_BUILTINS_COMPLEX
|
||||
#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT)
|
||||
#endif
|
||||
|
||||
// Enable features which improve CPython compatibility
|
||||
@@ -179,36 +259,161 @@ typedef double mp_float_t;
|
||||
#define MICROPY_CPYTHON_COMPAT (1)
|
||||
#endif
|
||||
|
||||
// Maximum length of a path in the filesystem
|
||||
// So we can allocate a buffer on the stack for path manipulation in import
|
||||
#ifndef MICROPY_PATH_MAX
|
||||
#define MICROPY_PATH_MAX (512)
|
||||
// Whether POSIX-semantics non-blocking streams are supported
|
||||
#ifndef MICROPY_STREAMS_NON_BLOCK
|
||||
#define MICROPY_STREAMS_NON_BLOCK (0)
|
||||
#endif
|
||||
|
||||
// Whether to use computed gotos in the VM, or a switch
|
||||
// Computed gotos are roughly 10% faster, and increase VM code size by a little
|
||||
#ifndef MICROPY_USE_COMPUTED_GOTO
|
||||
#define MICROPY_USE_COMPUTED_GOTO (0)
|
||||
/*****************************************************************************/
|
||||
/* Fine control over Python builtins, classes, modules, etc */
|
||||
|
||||
// Whether str object is proper unicode
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
|
||||
#endif
|
||||
|
||||
// Whether to support bytearray object
|
||||
#ifndef MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#endif
|
||||
|
||||
// Whether to support set object
|
||||
#ifndef MICROPY_PY_BUILTINS_SET
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
#endif
|
||||
|
||||
// Whether to support slice subscript operators and slice object
|
||||
#ifndef MICROPY_PY_BUILTINS_SLICE
|
||||
#define MICROPY_PY_BUILTINS_SLICE (1)
|
||||
#endif
|
||||
|
||||
// Whether to support frozenset object
|
||||
#ifndef MICROPY_PY_BUILTINS_FROZENSET
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#endif
|
||||
|
||||
// Whether to support property object
|
||||
#ifndef MICROPY_PY_BUILTINS_PROPERTY
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||
#endif
|
||||
|
||||
// Whether to set __file__ for imported modules
|
||||
#ifndef MICROPY_PY___FILE__
|
||||
#define MICROPY_PY___FILE__ (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "array" module. Note that large chunk of the
|
||||
// underlying code is shared with "bytearray" builtin type, so to
|
||||
// get real savings, it should be disabled too.
|
||||
#ifndef MICROPY_PY_ARRAY
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "collections" module
|
||||
#ifndef MICROPY_PY_COLLECTIONS
|
||||
#define MICROPY_PY_COLLECTIONS (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "math" module
|
||||
#ifndef MICROPY_PY_MATH
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "cmath" module
|
||||
#ifndef MICROPY_PY_CMATH
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "gc" module
|
||||
#ifndef MICROPY_PY_GC
|
||||
#define MICROPY_PY_GC (1)
|
||||
#endif
|
||||
|
||||
// Whether to return number of collected objects from gc.collect()
|
||||
#ifndef MICROPY_PY_GC_COLLECT_RETVAL
|
||||
#define MICROPY_PY_GC_COLLECT_RETVAL (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io" module
|
||||
#ifndef MICROPY_PY_IO
|
||||
#define MICROPY_PY_IO (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io.FileIO" class
|
||||
#ifndef MICROPY_PY_IO_FILEIO
|
||||
#define MICROPY_PY_IO_FILEIO (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io.BytesIO" class
|
||||
#ifndef MICROPY_PY_IO_BYTESIO
|
||||
#define MICROPY_PY_IO_BYTESIO (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "struct" module
|
||||
#ifndef MICROPY_PY_STRUCT
|
||||
#define MICROPY_PY_STRUCT (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys" module
|
||||
#ifndef MICROPY_PY_SYS
|
||||
#define MICROPY_PY_SYS (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys.maxsize" constant
|
||||
#ifndef MICROPY_PY_SYS_MAXSIZE
|
||||
#define MICROPY_PY_SYS_MAXSIZE (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys.exit" function
|
||||
#ifndef MICROPY_PY_SYS_EXIT
|
||||
#define MICROPY_PY_SYS_EXIT (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide sys.{stdin,stdout,stderr} objects
|
||||
#ifndef MICROPY_PY_SYS_STDFILES
|
||||
#define MICROPY_PY_SYS_STDFILES (0)
|
||||
#endif
|
||||
|
||||
|
||||
// Extended modules
|
||||
|
||||
#ifndef MICROPY_PY_UCTYPES
|
||||
#define MICROPY_PY_UCTYPES (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_ZLIBD
|
||||
#define MICROPY_PY_ZLIBD (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to add builtins */
|
||||
|
||||
// Additional builtin function definitions - see builtintables.c:builtin_object_table for format.
|
||||
#ifndef MICROPY_EXTRA_BUILTINS
|
||||
#define MICROPY_EXTRA_BUILTINS
|
||||
#ifndef MICROPY_PORT_BUILTINS
|
||||
#define MICROPY_PORT_BUILTINS
|
||||
#endif
|
||||
|
||||
// Additional builtin module definitions - see builtintables.c:builtin_module_table for format.
|
||||
#ifndef MICROPY_EXTRA_BUILTIN_MODULES
|
||||
#define MICROPY_EXTRA_BUILTIN_MODULES
|
||||
#ifndef MICROPY_PORT_BUILTIN_MODULES
|
||||
#define MICROPY_PORT_BUILTIN_MODULES
|
||||
#endif
|
||||
|
||||
// Additional constant definitions for the compiler - see compile.c:mp_constants_table.
|
||||
#ifndef MICROPY_EXTRA_CONSTANTS
|
||||
#define MICROPY_EXTRA_CONSTANTS
|
||||
#ifndef MICROPY_PORT_CONSTANTS
|
||||
#define MICROPY_PORT_CONSTANTS
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Miscellaneous settings */
|
||||
|
||||
// On embedded platforms, these will typically enable/disable irqs.
|
||||
#ifndef MICROPY_BEGIN_ATOMIC_SECTION
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION()
|
||||
#endif
|
||||
#ifndef MICROPY_END_ATOMIC_SECTION
|
||||
#define MICROPY_END_ATOMIC_SECTION()
|
||||
#endif
|
||||
|
||||
// Allow to override static modifier for global objects, e.g. to use with
|
||||
// object code analysis tools which don't support static symbols.
|
||||
#ifndef STATIC
|
||||
@@ -217,8 +422,8 @@ typedef double mp_float_t;
|
||||
|
||||
#define BITS_PER_BYTE (8)
|
||||
#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
|
||||
// machine_int_t value with most significant bit set
|
||||
#define WORD_MSBIT_HIGH (((machine_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
|
||||
// mp_int_t value with most significant bit set
|
||||
#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
|
||||
|
||||
#if !defined(MP_ENDIANNESS_LITTLE) && !defined(MP_ENDIANNESS_BIG)
|
||||
// Just because most archs are such?
|
||||
@@ -229,18 +434,31 @@ typedef double mp_float_t;
|
||||
#define MP_ENDIANNESS_LITTLE (0)
|
||||
#endif
|
||||
|
||||
// printf format spec to use for machine_int_t and friends
|
||||
// Make a pointer to RAM callable (eg set lower bit for Thumb code)
|
||||
// (This scheme won't work if we want to mix Thumb and normal ARM code.)
|
||||
#ifndef MICROPY_MAKE_POINTER_CALLABLE
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
|
||||
#endif
|
||||
|
||||
// printf format spec to use for mp_int_t and friends
|
||||
#ifndef INT_FMT
|
||||
#ifdef __LP64__
|
||||
// Archs where machine_int_t == long, long != int
|
||||
// Archs where mp_int_t == long, long != int
|
||||
#define UINT_FMT "%lu"
|
||||
#define INT_FMT "%ld"
|
||||
#else
|
||||
// Archs where machine_int_t == int
|
||||
// Archs where mp_int_t == int
|
||||
#define UINT_FMT "%u"
|
||||
#define INT_FMT "%d"
|
||||
#endif
|
||||
#endif //INT_FMT
|
||||
|
||||
// Modifier for function which doesn't return
|
||||
#ifndef NORETURN
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
// Modifier for weak functions
|
||||
#ifndef MP_WEAK
|
||||
#define MP_WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
194
py/mpz.c
194
py/mpz.c
@@ -1,11 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "mpz.h"
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
|
||||
@@ -63,12 +89,12 @@ STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
|
||||
mpz_dbl_dig_t d = 0;
|
||||
for (uint i = jlen; i > 0; i--, idig--, jdig--) {
|
||||
d |= *jdig;
|
||||
*idig = d >> (DIG_SIZE - n_part);
|
||||
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
|
||||
d <<= DIG_SIZE;
|
||||
}
|
||||
|
||||
// store remaining bits
|
||||
*idig = d >> (DIG_SIZE - n_part);
|
||||
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
|
||||
idig -= n_whole - 1;
|
||||
memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
|
||||
|
||||
@@ -181,17 +207,47 @@ STATIC uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
|
||||
STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
|
||||
mpz_dig_t *oidig = idig;
|
||||
|
||||
jlen -= klen;
|
||||
|
||||
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
|
||||
*idig = *jdig & *kdig;
|
||||
}
|
||||
|
||||
for (; jlen > 0; --jlen, ++idig) {
|
||||
*idig = 0;
|
||||
// remove trailing zeros
|
||||
for (--idig; idig >= oidig && *idig == 0; --idig) {
|
||||
}
|
||||
|
||||
return idig - oidig;
|
||||
return idig + 1 - oidig;
|
||||
}
|
||||
|
||||
/* computes i = j & -k = j & (~k + 1)
|
||||
returns number of digits in i
|
||||
assumes enough memory in i; assumes normalised j, k
|
||||
can have i, j, k pointing to same memory
|
||||
*/
|
||||
STATIC uint mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
|
||||
mpz_dig_t *oidig = idig;
|
||||
mpz_dbl_dig_t carry = 1;
|
||||
|
||||
for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) {
|
||||
carry += *kdig ^ DIG_MASK;
|
||||
*idig = (*jdig & carry) & DIG_MASK;
|
||||
carry >>= DIG_SIZE;
|
||||
}
|
||||
|
||||
for (; jlen > 0; --jlen, ++idig, ++jdig) {
|
||||
carry += DIG_MASK;
|
||||
*idig = (*jdig & carry) & DIG_MASK;
|
||||
carry >>= DIG_SIZE;
|
||||
}
|
||||
|
||||
if (carry != 0) {
|
||||
*idig = carry;
|
||||
} else {
|
||||
// remove trailing zeros
|
||||
for (--idig; idig >= oidig && *idig == 0; --idig) {
|
||||
}
|
||||
}
|
||||
|
||||
return idig + 1 - oidig;
|
||||
}
|
||||
|
||||
/* computes i = j | k
|
||||
@@ -295,7 +351,7 @@ STATIC uint mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, mpz_dig_t *kdig
|
||||
modifies den_dig memory, but restors it to original state at end
|
||||
*/
|
||||
|
||||
STATIC void mpn_div(mpz_dig_t *num_dig, machine_uint_t *num_len, mpz_dig_t *den_dig, machine_uint_t den_len, mpz_dig_t *quo_dig, machine_uint_t *quo_len) {
|
||||
STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) {
|
||||
mpz_dig_t *orig_num_dig = num_dig;
|
||||
mpz_dig_t *orig_quo_dig = quo_dig;
|
||||
mpz_dig_t norm_shift = 0;
|
||||
@@ -446,12 +502,12 @@ void mpz_init_zero(mpz_t *z) {
|
||||
z->dig = NULL;
|
||||
}
|
||||
|
||||
void mpz_init_from_int(mpz_t *z, machine_int_t val) {
|
||||
void mpz_init_from_int(mpz_t *z, mp_int_t val) {
|
||||
mpz_init_zero(z);
|
||||
mpz_set_from_int(z, val);
|
||||
}
|
||||
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, machine_int_t val) {
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, mp_int_t val) {
|
||||
z->neg = 0;
|
||||
z->fixed_dig = 1;
|
||||
z->alloc = alloc;
|
||||
@@ -472,7 +528,7 @@ mpz_t *mpz_zero(void) {
|
||||
return z;
|
||||
}
|
||||
|
||||
mpz_t *mpz_from_int(machine_int_t val) {
|
||||
mpz_t *mpz_from_int(mp_int_t val) {
|
||||
mpz_t *z = mpz_zero();
|
||||
mpz_set_from_int(z, val);
|
||||
return z;
|
||||
@@ -538,10 +594,10 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
|
||||
memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
|
||||
}
|
||||
|
||||
void mpz_set_from_int(mpz_t *z, machine_int_t val) {
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
|
||||
mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
|
||||
|
||||
machine_uint_t uval;
|
||||
mp_uint_t uval;
|
||||
if (val < 0) {
|
||||
z->neg = 1;
|
||||
uval = -val;
|
||||
@@ -648,7 +704,7 @@ int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
|
||||
#if 0
|
||||
// obsolete
|
||||
// compares mpz with an integer that fits within DIG_SIZE bits
|
||||
int mpz_cmp_sml_int(const mpz_t *z, machine_int_t sml_int) {
|
||||
int mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
|
||||
int cmp;
|
||||
if (z->neg == 0) {
|
||||
if (sml_int < 0) return 1;
|
||||
@@ -774,7 +830,7 @@ void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
|
||||
/* computes dest = lhs << rhs
|
||||
can have dest, lhs the same
|
||||
*/
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
|
||||
if (lhs->len == 0 || rhs == 0) {
|
||||
mpz_set(dest, lhs);
|
||||
} else if (rhs < 0) {
|
||||
@@ -789,7 +845,7 @@ void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
|
||||
/* computes dest = lhs >> rhs
|
||||
can have dest, lhs the same
|
||||
*/
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
|
||||
if (lhs->len == 0 || rhs == 0) {
|
||||
mpz_set(dest, lhs);
|
||||
} else if (rhs < 0) {
|
||||
@@ -872,23 +928,35 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
|
||||
can have dest, lhs, rhs the same
|
||||
*/
|
||||
void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
|
||||
if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
|
||||
const mpz_t *temp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = temp;
|
||||
}
|
||||
|
||||
if (lhs->neg == rhs->neg) {
|
||||
mpz_need_dig(dest, lhs->len);
|
||||
dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
if (lhs->neg == 0) {
|
||||
// make sure lhs has the most digits
|
||||
if (lhs->len < rhs->len) {
|
||||
const mpz_t *temp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = temp;
|
||||
}
|
||||
// do the and'ing
|
||||
mpz_need_dig(dest, rhs->len);
|
||||
dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
dest->neg = 0;
|
||||
} else {
|
||||
// TODO both args are negative
|
||||
assert(0);
|
||||
}
|
||||
} else {
|
||||
mpz_need_dig(dest, lhs->len);
|
||||
// TODO
|
||||
assert(0);
|
||||
// dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
// args have different sign
|
||||
// make sure lhs is the positive arg
|
||||
if (rhs->neg == 0) {
|
||||
const mpz_t *temp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = temp;
|
||||
}
|
||||
mpz_need_dig(dest, lhs->len + 1);
|
||||
dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
assert(dest->len <= dest->alloc);
|
||||
dest->neg = 0;
|
||||
}
|
||||
|
||||
dest->neg = lhs->neg;
|
||||
}
|
||||
|
||||
/* computes dest = lhs | rhs
|
||||
@@ -1064,10 +1132,10 @@ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
|
||||
lcm(0, 0) = 0
|
||||
lcm(z, 0) = 0
|
||||
*/
|
||||
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2)
|
||||
{
|
||||
if (z1->len == 0 || z2->len == 0)
|
||||
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
|
||||
if (z1->len == 0 || z2->len == 0) {
|
||||
return mpz_zero();
|
||||
}
|
||||
|
||||
mpz_t *gcd = mpz_gcd(z1, z2);
|
||||
mpz_t *quo = mpz_zero();
|
||||
@@ -1142,45 +1210,32 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO check that this correctly handles overflow in all cases
|
||||
machine_int_t mpz_as_int(const mpz_t *i) {
|
||||
machine_int_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
// must return actual int value if it fits in mp_int_t
|
||||
mp_int_t mpz_hash(const mpz_t *z) {
|
||||
mp_int_t val = 0;
|
||||
mpz_dig_t *d = z->dig + z->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
machine_int_t oldval = val;
|
||||
while (--d >= z->dig) {
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
if (val < oldval) {
|
||||
// overflow, return +/- "infinity"
|
||||
if (i->neg == 0) {
|
||||
// +infinity
|
||||
return ~WORD_MSBIT_HIGH;
|
||||
} else {
|
||||
// -infinity
|
||||
return WORD_MSBIT_HIGH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i->neg != 0) {
|
||||
if (z->neg != 0) {
|
||||
val = -val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// TODO check that this correctly handles overflow in all cases
|
||||
bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
|
||||
machine_int_t val = 0;
|
||||
bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
|
||||
mp_int_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
machine_int_t oldval = val;
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
if (val < oldval) {
|
||||
// overflow
|
||||
if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
|
||||
// will overflow
|
||||
return false;
|
||||
}
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
}
|
||||
|
||||
if (i->neg != 0) {
|
||||
@@ -1191,7 +1246,28 @@ bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
|
||||
if (i->neg != 0) {
|
||||
// can't represent signed values
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_uint_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
if (val > ((~0) >> DIG_SIZE)) {
|
||||
// will overflow
|
||||
return false;
|
||||
}
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
}
|
||||
|
||||
*value = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mpz_as_float(const mpz_t *i) {
|
||||
mp_float_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
55
py/mpz.h
55
py/mpz.h
@@ -1,29 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef uint16_t mpz_dig_t;
|
||||
typedef uint32_t mpz_dbl_dig_t;
|
||||
typedef int32_t mpz_dbl_dig_signed_t;
|
||||
|
||||
typedef struct _mpz_t {
|
||||
machine_uint_t neg : 1;
|
||||
machine_uint_t fixed_dig : 1;
|
||||
machine_uint_t alloc : 30;
|
||||
machine_uint_t len;
|
||||
mp_uint_t neg : 1;
|
||||
mp_uint_t fixed_dig : 1;
|
||||
mp_uint_t alloc : 30;
|
||||
mp_uint_t len;
|
||||
mpz_dig_t *dig;
|
||||
} mpz_t;
|
||||
|
||||
#define MPZ_DIG_SIZE (15) // see mpn_div for why this needs to be at most 15
|
||||
#define MPZ_NUM_DIG_FOR_INT (sizeof(machine_int_t) * 8 / MPZ_DIG_SIZE + 1)
|
||||
#define MPZ_NUM_DIG_FOR_INT (sizeof(mp_int_t) * 8 / MPZ_DIG_SIZE + 1)
|
||||
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
|
||||
|
||||
// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer
|
||||
#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
|
||||
|
||||
void mpz_init_zero(mpz_t *z);
|
||||
void mpz_init_from_int(mpz_t *z, machine_int_t val);
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, machine_int_t val);
|
||||
void mpz_init_from_int(mpz_t *z, mp_int_t val);
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, mp_int_t val);
|
||||
void mpz_deinit(mpz_t *z);
|
||||
|
||||
mpz_t *mpz_zero();
|
||||
mpz_t *mpz_from_int(machine_int_t i);
|
||||
mpz_t *mpz_from_int(mp_int_t i);
|
||||
mpz_t *mpz_from_ll(long long i);
|
||||
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base);
|
||||
void mpz_free(mpz_t *z);
|
||||
@@ -31,7 +57,7 @@ void mpz_free(mpz_t *z);
|
||||
mpz_t *mpz_clone(const mpz_t *src);
|
||||
|
||||
void mpz_set(mpz_t *dest, const mpz_t *src);
|
||||
void mpz_set_from_int(mpz_t *z, machine_int_t src);
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t src);
|
||||
void mpz_set_from_ll(mpz_t *z, long long i);
|
||||
uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base);
|
||||
|
||||
@@ -53,8 +79,8 @@ mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs);
|
||||
void mpz_abs_inpl(mpz_t *dest, const mpz_t *z);
|
||||
void mpz_neg_inpl(mpz_t *dest, const mpz_t *z);
|
||||
void mpz_not_inpl(mpz_t *dest, const mpz_t *z);
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs);
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs);
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs);
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs);
|
||||
void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
|
||||
void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
|
||||
void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
|
||||
@@ -70,9 +96,10 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
|
||||
mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs);
|
||||
mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs);
|
||||
|
||||
machine_int_t mpz_as_int(const mpz_t *z);
|
||||
bool mpz_as_int_checked(const mpz_t *z, machine_int_t *value);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
mp_int_t mpz_hash(const mpz_t *z);
|
||||
bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);
|
||||
bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mpz_as_float(const mpz_t *z);
|
||||
#endif
|
||||
uint mpz_as_str_size(const mpz_t *z, uint base);
|
||||
|
||||
136
py/nativeglue.c
Normal file
136
py/nativeglue.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "emitglue.h"
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
// convert a Micro Python object to a valid native value based on type
|
||||
mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) {
|
||||
DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type);
|
||||
switch (type & 3) {
|
||||
case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
|
||||
case MP_NATIVE_TYPE_BOOL:
|
||||
case MP_NATIVE_TYPE_INT:
|
||||
case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
|
||||
default: assert(0); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// convert a native value to a Micro Python object based on type
|
||||
mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) {
|
||||
DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
|
||||
switch (type & 3) {
|
||||
case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
|
||||
case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
|
||||
case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
|
||||
case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
|
||||
default: assert(0); return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
// wrapper that accepts n_args and n_kw in one argument
|
||||
// (native emitter can only pass at most 3 arguments to a function)
|
||||
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args) {
|
||||
return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
|
||||
}
|
||||
|
||||
// wrapper that makes raise obj and raises it
|
||||
NORETURN void mp_native_raise(mp_obj_t o) {
|
||||
nlr_raise(mp_make_raise_obj(o));
|
||||
}
|
||||
|
||||
// these must correspond to the respective enum in runtime0.h
|
||||
void *const mp_fun_table[MP_F_NUMBER_OF] = {
|
||||
mp_convert_obj_to_native,
|
||||
mp_convert_native_to_obj,
|
||||
mp_load_const_int,
|
||||
mp_load_const_dec,
|
||||
mp_load_const_str,
|
||||
mp_load_const_bytes,
|
||||
mp_load_name,
|
||||
mp_load_global,
|
||||
mp_load_build_class,
|
||||
mp_load_attr,
|
||||
mp_load_method,
|
||||
mp_store_name,
|
||||
mp_store_global,
|
||||
mp_store_attr,
|
||||
mp_obj_subscr,
|
||||
mp_obj_is_true,
|
||||
mp_unary_op,
|
||||
mp_binary_op,
|
||||
mp_obj_new_tuple,
|
||||
mp_obj_new_list,
|
||||
mp_obj_list_append,
|
||||
mp_obj_new_dict,
|
||||
mp_obj_dict_store,
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
mp_obj_new_set,
|
||||
mp_obj_set_store,
|
||||
#endif
|
||||
mp_make_function_from_raw_code,
|
||||
mp_native_call_function_n_kw,
|
||||
mp_call_method_n_kw,
|
||||
mp_getiter,
|
||||
mp_iternext,
|
||||
nlr_push,
|
||||
nlr_pop,
|
||||
mp_native_raise,
|
||||
mp_import_name,
|
||||
mp_import_from,
|
||||
mp_import_all,
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
mp_obj_new_slice,
|
||||
#endif
|
||||
mp_unpack_sequence,
|
||||
mp_unpack_ex,
|
||||
};
|
||||
|
||||
/*
|
||||
void mp_f_vector(mp_fun_kind_t fun_kind) {
|
||||
(mp_f_table[fun_kind])();
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
29
py/nlr.h
29
py/nlr.h
@@ -1,8 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// non-local return
|
||||
// exception handling, basically a stack of setjmp/longjmp buffers
|
||||
|
||||
#include <limits.h>
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct _nlr_buf_t nlr_buf_t;
|
||||
struct _nlr_buf_t {
|
||||
@@ -18,7 +45,7 @@ struct _nlr_buf_t {
|
||||
#else
|
||||
void *regs[8];
|
||||
#endif
|
||||
#elif defined(__thumb2__)
|
||||
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
|
||||
void *regs[10];
|
||||
#else
|
||||
#define MICROPY_NLR_SETJMP (1)
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include "mpconfig.h"
|
||||
|
||||
@@ -1,16 +1,44 @@
|
||||
#if defined(__thumb2__) && !MICROPY_NLR_SETJMP
|
||||
/* thumb callee save: bx, bp, sp, r12, r14, r14, r15 */
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !MICROPY_NLR_SETJMP && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
|
||||
/* arm callee save: bx, bp, sp, r12, r14, r14, r15 */
|
||||
|
||||
.syntax unified
|
||||
/*.cpu cortex-m4*/
|
||||
.thumb
|
||||
/*.thumb*/
|
||||
.text
|
||||
.align 2
|
||||
|
||||
/* uint nlr_push(r0=nlr_buf_t *nlr) */
|
||||
.global nlr_push
|
||||
#if defined(__thumb2__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
.type nlr_push, %function
|
||||
nlr_push:
|
||||
str lr, [r0, #8] @ store lr into nlr_buf
|
||||
@@ -38,8 +66,10 @@ nlr_push:
|
||||
|
||||
@ void nlr_pop()
|
||||
.global nlr_pop
|
||||
#if defined(__thumb2__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
.type nlr_pop, %function
|
||||
nlr_pop:
|
||||
ldr r3, .L5 @ load addr of nlr_top
|
||||
@@ -54,8 +84,10 @@ nlr_pop:
|
||||
|
||||
/* void nlr_jump(r0=uint val) */
|
||||
.global nlr_jump
|
||||
#if defined(__thumb2__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
.type nlr_jump, %function
|
||||
nlr_jump:
|
||||
ldr r3, .L2 @ load addr of nlr_top
|
||||
|
||||
30
py/nlrx64.S
30
py/nlrx64.S
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(__x86_64__) && !MICROPY_NLR_SETJMP
|
||||
/* x64 callee save: bx, bp, sp, r12, r13, r14, r15 */
|
||||
|
||||
@@ -6,6 +32,10 @@
|
||||
|
||||
#if !defined(__CYGWIN__)
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#define nlr_jump_fail _nlr_jump_fail
|
||||
#endif // (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
/* uint nlr_push(rdi=nlr_buf_t *nlr) */
|
||||
#if !(defined(__APPLE__) && defined(__MACH__))
|
||||
.globl nlr_push
|
||||
|
||||
26
py/nlrx86.S
26
py/nlrx86.S
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(__i386__) && !MICROPY_NLR_SETJMP
|
||||
/* x86 callee save: bx, di, si, bp, sp */
|
||||
|
||||
|
||||
99
py/obj.c
99
py/obj.c
@@ -1,3 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
@@ -7,21 +34,24 @@
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "stackctrl.h"
|
||||
|
||||
mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in) {
|
||||
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
return (mp_obj_t)&mp_type_int;
|
||||
} else if (MP_OBJ_IS_QSTR(o_in)) {
|
||||
return (mp_obj_t)&mp_type_str;
|
||||
} else {
|
||||
mp_obj_base_t *o = o_in;
|
||||
const mp_obj_base_t *o = o_in;
|
||||
return (mp_obj_t)o->type;
|
||||
}
|
||||
}
|
||||
|
||||
const char *mp_obj_get_type_str(mp_obj_t o_in) {
|
||||
const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
|
||||
return qstr_str(mp_obj_get_type(o_in)->name);
|
||||
}
|
||||
|
||||
@@ -33,6 +63,14 @@ void printf_wrapper(void *env, const char *fmt, ...) {
|
||||
}
|
||||
|
||||
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
// There can be data structures nested too deep, or just recursive
|
||||
MP_STACK_CHECK();
|
||||
#if !NDEBUG
|
||||
if (o_in == NULL) {
|
||||
print(env, "(nil)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mp_obj_type_t *type = mp_obj_get_type(o_in);
|
||||
if (type->print != NULL) {
|
||||
type->print(print, env, o_in, kind);
|
||||
@@ -48,7 +86,7 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
// helper function to print an exception with traceback
|
||||
void mp_obj_print_exception(mp_obj_t exc) {
|
||||
if (mp_obj_is_exception_instance(exc)) {
|
||||
machine_uint_t n, *values;
|
||||
mp_uint_t n, *values;
|
||||
mp_obj_exception_get_traceback(exc, &n, &values);
|
||||
if (n > 0) {
|
||||
assert(n % 3 == 0);
|
||||
@@ -90,7 +128,7 @@ int mp_obj_is_true(mp_obj_t arg) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(arg);
|
||||
if (type->unary_op != NULL) {
|
||||
mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
|
||||
if (result != MP_OBJ_NOT_SUPPORTED) {
|
||||
if (result != MP_OBJ_NULL) {
|
||||
return result == mp_const_true;
|
||||
}
|
||||
}
|
||||
@@ -110,23 +148,25 @@ bool mp_obj_is_callable(mp_obj_t o_in) {
|
||||
return mp_obj_get_type(o_in)->call != NULL;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_hash(mp_obj_t o_in) {
|
||||
mp_int_t mp_obj_hash(mp_obj_t o_in) {
|
||||
if (o_in == mp_const_false) {
|
||||
return 0; // needs to hash to same as the integer 0, since False==0
|
||||
} else if (o_in == mp_const_true) {
|
||||
return 1; // needs to hash to same as the integer 1, since True==1
|
||||
} else if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_int)) {
|
||||
return mp_obj_int_hash(o_in);
|
||||
} else if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
|
||||
return mp_obj_str_get_hash(o_in);
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) {
|
||||
return (machine_int_t)o_in;
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_fun_native) || MP_OBJ_IS_TYPE(o_in, &mp_type_fun_bc)) {
|
||||
return (machine_int_t)o_in;
|
||||
return (mp_int_t)o_in;
|
||||
} else if (MP_OBJ_IS_FUN(o_in)) {
|
||||
return (mp_int_t)o_in;
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) {
|
||||
return mp_obj_tuple_hash(o_in);
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_type)) {
|
||||
return (machine_int_t)o_in;
|
||||
return (mp_int_t)o_in;
|
||||
|
||||
// TODO hash class and instances
|
||||
// TODO delegate to __hash__ method if it exists
|
||||
@@ -180,7 +220,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(o1);
|
||||
if (type->binary_op != NULL) {
|
||||
mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
|
||||
if (r != MP_OBJ_NOT_SUPPORTED) {
|
||||
if (r != MP_OBJ_NULL) {
|
||||
return r == mp_const_true ? true : false;
|
||||
}
|
||||
}
|
||||
@@ -190,7 +230,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_get_int(mp_obj_t arg) {
|
||||
mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
|
||||
// This function essentially performs implicit type conversion to int
|
||||
// Note that Python does NOT provide implicit type conversion from
|
||||
// float to int in the core expression language, try some_list[1.0].
|
||||
@@ -209,8 +249,8 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) {
|
||||
|
||||
// returns false if arg is not of integral type
|
||||
// returns true and sets *value if it is of integral type
|
||||
// can throw OverflowError if arg is of integral type, but doesn't fit in a machine_int_t
|
||||
bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) {
|
||||
// can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {
|
||||
if (arg == mp_const_false) {
|
||||
*value = 0;
|
||||
} else if (arg == mp_const_true) {
|
||||
@@ -225,7 +265,7 @@ bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_get_float(mp_obj_t arg) {
|
||||
if (arg == mp_const_false) {
|
||||
return 0;
|
||||
@@ -242,6 +282,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
|
||||
if (arg == mp_const_false) {
|
||||
*real = 0;
|
||||
@@ -265,6 +306,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
|
||||
if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
|
||||
@@ -293,8 +335,8 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
|
||||
}
|
||||
|
||||
// is_slice determines whether the index is a slice index
|
||||
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice) {
|
||||
machine_int_t i;
|
||||
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) {
|
||||
mp_int_t i;
|
||||
if (MP_OBJ_IS_SMALL_INT(index)) {
|
||||
i = MP_OBJ_SMALL_INT_VALUE(index);
|
||||
} else if (!mp_obj_get_int_maybe(index, &i)) {
|
||||
@@ -318,10 +360,25 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index,
|
||||
return i;
|
||||
}
|
||||
|
||||
// will raise a TypeError if object has no length
|
||||
mp_obj_t mp_obj_len(mp_obj_t o_in) {
|
||||
mp_obj_t len = mp_obj_len_maybe(o_in);
|
||||
if (len == MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
|
||||
} else {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
// may return MP_OBJ_NULL
|
||||
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
|
||||
if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in));
|
||||
if (
|
||||
#if !MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
// It's simple - unicode is slow, non-unicode is fast
|
||||
MP_OBJ_IS_STR(o_in) ||
|
||||
#endif
|
||||
MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_obj_str_get_len(o_in));
|
||||
} else {
|
||||
mp_obj_type_t *type = mp_obj_get_type(o_in);
|
||||
if (type->unary_op != NULL) {
|
||||
@@ -336,7 +393,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(base);
|
||||
if (type->subscr != NULL) {
|
||||
mp_obj_t ret = type->subscr(base, index, value);
|
||||
if (ret != MP_OBJ_NOT_SUPPORTED) {
|
||||
if (ret != MP_OBJ_NULL) {
|
||||
return ret;
|
||||
}
|
||||
// TODO: call base classes here?
|
||||
@@ -363,7 +420,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags) {
|
||||
return false;
|
||||
}
|
||||
int ret = type->buffer_p.get_buffer(obj, bufinfo, flags);
|
||||
if (ret != 0 || bufinfo->buf == NULL) {
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
230
py/obj.h
230
py/obj.h
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// A Micro Python object is a machine word having the following form:
|
||||
// - xxxx...xxx1 : a small int, bits 1 and above are the value
|
||||
// - xxxx...xx10 : a qstr, bits 2 and above are the value
|
||||
@@ -9,11 +35,6 @@
|
||||
typedef machine_ptr_t mp_obj_t;
|
||||
typedef machine_const_ptr_t mp_const_obj_t;
|
||||
|
||||
// Integers that fit in a pointer have this type
|
||||
// (do we need to expose this in the public API?)
|
||||
|
||||
typedef machine_int_t mp_small_int_t;
|
||||
|
||||
// Anything that wants to be a Micro Python object must have
|
||||
// mp_obj_base_t as its first member (except small ints and qstrs)
|
||||
|
||||
@@ -26,8 +47,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
|
||||
// These fake objects are used to indicate certain things in arguments or return
|
||||
// values, and should only be used when explicitly allowed.
|
||||
//
|
||||
// - MP_OBJ_NULL : used to indicate the absence of an object.
|
||||
// - MP_OBJ_NOT_SUPPORTED : a return value that indicates an unsupported operation.
|
||||
// - MP_OBJ_NULL : used to indicate the absence of an object, or unsupported operation.
|
||||
// - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency.
|
||||
// - MP_OBJ_SENTINEL : used for various internal purposes where one needs
|
||||
// an object which is unique from all other objects, including MP_OBJ_NULL.
|
||||
@@ -37,42 +57,38 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
|
||||
|
||||
#if NDEBUG
|
||||
#define MP_OBJ_NULL ((mp_obj_t)0)
|
||||
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)0)
|
||||
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)0)
|
||||
#define MP_OBJ_SENTINEL ((mp_obj_t)4)
|
||||
#else
|
||||
#define MP_OBJ_NULL ((mp_obj_t)0)
|
||||
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)4)
|
||||
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)8)
|
||||
#define MP_OBJ_SENTINEL ((mp_obj_t)12)
|
||||
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)4)
|
||||
#define MP_OBJ_SENTINEL ((mp_obj_t)8)
|
||||
#endif
|
||||
|
||||
// These macros check for small int, qstr or object, and access small int and qstr values
|
||||
|
||||
// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
|
||||
#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))
|
||||
#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN)))
|
||||
#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
|
||||
// these macros have now become inline functions; see below
|
||||
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
|
||||
//#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
|
||||
//#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
|
||||
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking a string, use below macro for that
|
||||
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_int_t)(o)) & 1) != 0)
|
||||
//#define MP_OBJ_IS_QSTR(o) ((((mp_int_t)(o)) & 3) == 2)
|
||||
//#define MP_OBJ_IS_OBJ(o) ((((mp_int_t)(o)) & 3) == 0)
|
||||
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
|
||||
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
|
||||
#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str))
|
||||
#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)(o))->type->binary_op == mp_obj_str_binary_op))
|
||||
#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type->binary_op == mp_obj_fun_binary_op))
|
||||
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_small_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((small_int) << 1) | 1))
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
|
||||
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_small_int_t)(o)) >> 2)
|
||||
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((machine_uint_t)qstr) << 2) | 2))
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_int_t)(o)) >> 2)
|
||||
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((mp_uint_t)(qstr)) << 2) | 2))
|
||||
|
||||
// These macros are used to declare and define constant function objects
|
||||
// You can put "static" in front of the definitions to make them local
|
||||
|
||||
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_native_t obj_name
|
||||
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name
|
||||
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_native_t obj_name = {{&mp_type_fun_native}, is_kw, n_args_min, n_args_max, (void *)fun_name}
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_builtin_t obj_name = {{&mp_type_fun_builtin}, is_kw, n_args_min, n_args_max, (void *)fun_name}
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 0, 0, (mp_fun_0_t)fun_name)
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 1, 1, (mp_fun_1_t)fun_name)
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 2, 2, (mp_fun_2_t)fun_name)
|
||||
@@ -118,10 +134,10 @@ typedef struct _mp_map_elem_t {
|
||||
// would also need a trucated dict structure
|
||||
|
||||
typedef struct _mp_map_t {
|
||||
machine_uint_t all_keys_are_qstrs : 1;
|
||||
machine_uint_t table_is_fixed_array : 1;
|
||||
machine_uint_t used : (8 * sizeof(machine_uint_t) - 2);
|
||||
machine_uint_t alloc;
|
||||
mp_uint_t all_keys_are_qstrs : 1;
|
||||
mp_uint_t table_is_fixed_array : 1;
|
||||
mp_uint_t used : (8 * sizeof(mp_uint_t) - 2);
|
||||
mp_uint_t alloc;
|
||||
mp_map_elem_t *table;
|
||||
} mp_map_t;
|
||||
|
||||
@@ -132,7 +148,7 @@ typedef enum _mp_map_lookup_kind_t {
|
||||
MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2
|
||||
} mp_map_lookup_kind_t;
|
||||
|
||||
static inline bool MP_MAP_SLOT_IS_FILLED(mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
|
||||
static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, mp_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
|
||||
|
||||
void mp_map_init(mp_map_t *map, int n);
|
||||
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
|
||||
@@ -146,12 +162,12 @@ void mp_map_dump(mp_map_t *map);
|
||||
// Underlying set implementation (not set object)
|
||||
|
||||
typedef struct _mp_set_t {
|
||||
machine_uint_t alloc;
|
||||
machine_uint_t used;
|
||||
mp_uint_t alloc;
|
||||
mp_uint_t used;
|
||||
mp_obj_t *table;
|
||||
} mp_set_t;
|
||||
|
||||
static inline bool MP_SET_SLOT_IS_FILLED(mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
|
||||
static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, mp_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
|
||||
|
||||
void mp_set_init(mp_set_t *set, int n);
|
||||
mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
|
||||
@@ -164,7 +180,6 @@ typedef mp_obj_t (*mp_fun_0_t)(void);
|
||||
typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t);
|
||||
typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t);
|
||||
typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
|
||||
typedef mp_obj_t (*mp_fun_t)(void);
|
||||
typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *);
|
||||
typedef mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *);
|
||||
|
||||
@@ -196,8 +211,8 @@ typedef struct _mp_buffer_info_t {
|
||||
// them with ver = sizeof(struct). Cons: overkill for *micro*?
|
||||
//int ver; // ?
|
||||
|
||||
void *buf;
|
||||
machine_int_t len; // in bytes
|
||||
void *buf; // can be NULL if len == 0
|
||||
mp_int_t len; // in bytes
|
||||
int typecode; // as per binary.h
|
||||
|
||||
// Rationale: to load arbitrary-sized sprites directly to LCD
|
||||
@@ -208,18 +223,20 @@ typedef struct _mp_buffer_info_t {
|
||||
#define MP_BUFFER_WRITE (2)
|
||||
#define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE)
|
||||
typedef struct _mp_buffer_p_t {
|
||||
machine_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
} mp_buffer_p_t;
|
||||
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
// Stream protocol
|
||||
#define MP_STREAM_ERROR (-1)
|
||||
typedef struct _mp_stream_p_t {
|
||||
// On error, functions should return -1 and fill in *errcode (values are
|
||||
// implementation-dependent, but will be exposed to user, e.g. via exception).
|
||||
machine_int_t (*read)(mp_obj_t obj, void *buf, machine_uint_t size, int *errcode);
|
||||
machine_int_t (*write)(mp_obj_t obj, const void *buf, machine_uint_t size, int *errcode);
|
||||
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
|
||||
// are implementation-dependent, but will be exposed to user, e.g. via exception).
|
||||
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
|
||||
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
|
||||
// add seek() ?
|
||||
int is_text : 1; // default is bytes, set this for text stream
|
||||
} mp_stream_p_t;
|
||||
|
||||
struct _mp_obj_type_t {
|
||||
@@ -229,18 +246,18 @@ struct _mp_obj_type_t {
|
||||
mp_make_new_fun_t make_new; // to make an instance of the type
|
||||
|
||||
mp_call_fun_t call;
|
||||
mp_unary_op_fun_t unary_op; // can return NULL if op not supported
|
||||
mp_binary_op_fun_t binary_op; // can return NULL if op not supported
|
||||
mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported
|
||||
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported
|
||||
|
||||
mp_load_attr_fun_t load_attr;
|
||||
mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute
|
||||
|
||||
mp_subscr_fun_t subscr; // implements load, store, delete subscripting
|
||||
// value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store
|
||||
// can return MP_OBJ_NOT_SUPPORTED
|
||||
// can return MP_OBJ_NULL if op not supported
|
||||
|
||||
mp_fun_1_t getiter;
|
||||
mp_fun_1_t iternext; // may return MP_OBJ_NULL as an optimisation instead of raising StopIteration() (with no args)
|
||||
mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args)
|
||||
|
||||
mp_buffer_p_t buffer_p;
|
||||
const mp_stream_p_t *stream_p;
|
||||
@@ -282,18 +299,21 @@ extern const mp_obj_type_t mp_type_filter;
|
||||
extern const mp_obj_type_t mp_type_dict;
|
||||
extern const mp_obj_type_t mp_type_range;
|
||||
extern const mp_obj_type_t mp_type_set;
|
||||
extern const mp_obj_type_t mp_type_frozenset;
|
||||
extern const mp_obj_type_t mp_type_slice;
|
||||
extern const mp_obj_type_t mp_type_zip;
|
||||
extern const mp_obj_type_t mp_type_array;
|
||||
extern const mp_obj_type_t mp_type_super;
|
||||
extern const mp_obj_type_t mp_type_gen_instance;
|
||||
extern const mp_obj_type_t mp_type_fun_native;
|
||||
extern const mp_obj_type_t mp_type_fun_builtin;
|
||||
extern const mp_obj_type_t mp_type_fun_bc;
|
||||
extern const mp_obj_type_t mp_type_module;
|
||||
extern const mp_obj_type_t mp_type_staticmethod;
|
||||
extern const mp_obj_type_t mp_type_classmethod;
|
||||
extern const mp_obj_type_t mp_type_property;
|
||||
extern const mp_obj_type_t mp_type_stringio;
|
||||
extern const mp_obj_type_t mp_type_bytesio;
|
||||
extern const mp_obj_type_t mp_type_reversed;
|
||||
|
||||
// Exceptions
|
||||
extern const mp_obj_type_t mp_type_BaseException;
|
||||
@@ -318,6 +338,7 @@ extern const mp_obj_type_t mp_type_RuntimeError;
|
||||
extern const mp_obj_type_t mp_type_StopIteration;
|
||||
extern const mp_obj_type_t mp_type_SyntaxError;
|
||||
extern const mp_obj_type_t mp_type_SystemError;
|
||||
extern const mp_obj_type_t mp_type_SystemExit;
|
||||
extern const mp_obj_type_t mp_type_TypeError;
|
||||
extern const mp_obj_type_t mp_type_ValueError;
|
||||
extern const mp_obj_type_t mp_type_ZeroDivisionError;
|
||||
@@ -342,13 +363,13 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict);
|
||||
mp_obj_t mp_obj_new_none(void);
|
||||
mp_obj_t mp_obj_new_bool(bool value);
|
||||
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value);
|
||||
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
|
||||
mp_obj_t mp_obj_new_int_from_long_str(const char *s);
|
||||
mp_obj_t mp_obj_new_int(mp_int_t value);
|
||||
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
|
||||
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base);
|
||||
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
|
||||
mp_obj_t mp_obj_new_str(const byte* data, uint len, bool make_qstr_if_not_already);
|
||||
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already);
|
||||
mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_obj_t mp_obj_new_float(mp_float_t val);
|
||||
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
|
||||
#endif
|
||||
@@ -357,8 +378,10 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
|
||||
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, const byte *code);
|
||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
||||
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
|
||||
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data);
|
||||
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig);
|
||||
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data);
|
||||
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
|
||||
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
|
||||
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
|
||||
@@ -371,9 +394,10 @@ mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self);
|
||||
mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args);
|
||||
mp_obj_t mp_obj_new_module(qstr module_name);
|
||||
|
||||
mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in);
|
||||
const char *mp_obj_get_type_str(mp_obj_t o_in);
|
||||
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in);
|
||||
const char *mp_obj_get_type_str(mp_const_obj_t o_in);
|
||||
bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects
|
||||
mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type);
|
||||
|
||||
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
|
||||
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
|
||||
@@ -382,47 +406,48 @@ void mp_obj_print_exception(mp_obj_t exc);
|
||||
int mp_obj_is_true(mp_obj_t arg);
|
||||
|
||||
// TODO make these all lower case when they have proven themselves
|
||||
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 0); }
|
||||
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 1) != 0); }
|
||||
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); }
|
||||
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); }
|
||||
//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that
|
||||
//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int
|
||||
static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
|
||||
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 2); }
|
||||
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 2); }
|
||||
//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); }
|
||||
|
||||
bool mp_obj_is_callable(mp_obj_t o_in);
|
||||
machine_int_t mp_obj_hash(mp_obj_t o_in);
|
||||
mp_int_t mp_obj_hash(mp_obj_t o_in);
|
||||
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
|
||||
|
||||
machine_int_t mp_obj_get_int(mp_obj_t arg);
|
||||
bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_get_float(mp_obj_t self_in);
|
||||
void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
|
||||
#endif
|
||||
//qstr mp_obj_get_qstr(mp_obj_t arg);
|
||||
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items);
|
||||
void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items);
|
||||
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice);
|
||||
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice);
|
||||
mp_obj_t mp_obj_len(mp_obj_t o_in);
|
||||
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return MP_OBJ_NULL */
|
||||
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val);
|
||||
|
||||
// bool
|
||||
// TODO make lower case when it has proven itself
|
||||
static inline mp_obj_t MP_BOOL(machine_int_t x) { return x ? mp_const_true : mp_const_false; }
|
||||
static inline mp_obj_t MP_BOOL(mp_int_t x) { return x ? mp_const_true : mp_const_false; }
|
||||
|
||||
// cell
|
||||
mp_obj_t mp_obj_cell_get(mp_obj_t self_in);
|
||||
void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
|
||||
|
||||
// int
|
||||
// For long int, returns value truncated to machine_int_t
|
||||
machine_int_t mp_obj_int_get(mp_obj_t self_in);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
// For long int, returns value truncated to mp_int_t
|
||||
mp_int_t mp_obj_int_get(mp_const_obj_t self_in);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_int_as_float(mp_obj_t self_in);
|
||||
#endif
|
||||
// Will raise exception if value doesn't fit into machine_int_t
|
||||
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in);
|
||||
// Will raise exception if value doesn't fit into mp_int_t
|
||||
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
|
||||
|
||||
// exception
|
||||
#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
|
||||
@@ -430,41 +455,44 @@ bool mp_obj_is_exception_type(mp_obj_t self_in);
|
||||
bool mp_obj_is_exception_instance(mp_obj_t self_in);
|
||||
bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type);
|
||||
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block);
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values);
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block);
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values);
|
||||
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
|
||||
void mp_init_emergency_exception_buf(void);
|
||||
|
||||
// str
|
||||
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data);
|
||||
mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in);
|
||||
mp_obj_t mp_obj_str_builder_end_with_len(mp_obj_t o_in, mp_uint_t len);
|
||||
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2);
|
||||
uint mp_obj_str_get_hash(mp_obj_t self_in);
|
||||
uint mp_obj_str_get_len(mp_obj_t self_in);
|
||||
qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr
|
||||
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
|
||||
const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len);
|
||||
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len);
|
||||
mp_obj_t mp_obj_str_intern(mp_obj_t str);
|
||||
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len, bool is_bytes);
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
// float
|
||||
typedef struct _mp_obj_float_t {
|
||||
mp_obj_base_t base;
|
||||
mp_float_t value;
|
||||
} mp_obj_float_t;
|
||||
mp_float_t mp_obj_float_get(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL
|
||||
mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
|
||||
|
||||
// complex
|
||||
void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
|
||||
mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL
|
||||
mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported
|
||||
#endif
|
||||
|
||||
// tuple
|
||||
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
|
||||
void mp_obj_tuple_del(mp_obj_t self_in);
|
||||
machine_int_t mp_obj_tuple_hash(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
|
||||
|
||||
// list
|
||||
struct _mp_obj_list_t;
|
||||
@@ -482,6 +510,7 @@ typedef struct _mp_obj_dict_t {
|
||||
} mp_obj_dict_t;
|
||||
void mp_obj_dict_init(mp_obj_dict_t *dict, int n_args);
|
||||
uint mp_obj_dict_len(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);
|
||||
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
|
||||
mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);
|
||||
mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);
|
||||
@@ -490,7 +519,7 @@ mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);
|
||||
void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
|
||||
|
||||
// slice
|
||||
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step);
|
||||
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
|
||||
|
||||
// array
|
||||
uint mp_obj_array_len(mp_obj_t self_in);
|
||||
@@ -498,20 +527,16 @@ mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items);
|
||||
|
||||
// functions
|
||||
#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below
|
||||
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
|
||||
typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go in ROM
|
||||
mp_obj_base_t base;
|
||||
bool is_kw : 1;
|
||||
uint n_args_min : 15; // inclusive
|
||||
uint n_args_max : 16; // inclusive
|
||||
void *fun;
|
||||
// TODO add mp_map_t *globals
|
||||
// for const function objects, make an empty, const map
|
||||
// such functions won't be able to access the global scope, but that's probably okay
|
||||
} mp_obj_fun_native_t;
|
||||
mp_uint_t n_args_min : 15; // inclusive
|
||||
mp_uint_t n_args_max : 16; // inclusive
|
||||
void *fun; // must be a pointer to a callable function in ROM
|
||||
} mp_obj_fun_builtin_t;
|
||||
|
||||
bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
|
||||
uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2);
|
||||
const char *mp_obj_fun_get_name(mp_obj_t fun);
|
||||
mp_obj_t mp_obj_fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
||||
const char *mp_obj_fun_get_name(mp_const_obj_t fun);
|
||||
const char *mp_obj_code_get_name(const byte *code_info);
|
||||
|
||||
mp_obj_t mp_identity(mp_obj_t self);
|
||||
@@ -536,13 +561,34 @@ typedef struct _mp_obj_static_class_method_t {
|
||||
const mp_obj_t *mp_obj_property_get(mp_obj_t self_in);
|
||||
|
||||
// sequence helpers
|
||||
|
||||
// slice indexes resolved to particular sequence
|
||||
typedef struct {
|
||||
mp_uint_t start;
|
||||
mp_uint_t stop;
|
||||
mp_int_t step;
|
||||
} mp_bound_slice_t;
|
||||
|
||||
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest);
|
||||
bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end);
|
||||
#define m_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t))
|
||||
#define m_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); }
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);
|
||||
#endif
|
||||
#define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t))
|
||||
#define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); }
|
||||
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2);
|
||||
bool mp_seq_cmp_objs(int op, const mp_obj_t *items1, uint len1, const mp_obj_t *items2, uint len2);
|
||||
mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value);
|
||||
mp_obj_t mp_seq_extract_slice(uint len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
|
||||
// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems
|
||||
#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
|
||||
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_t) \
|
||||
/*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * sizeof(item_t));*/ \
|
||||
memcpy(dest + beg, slice, slice_len * sizeof(item_t)); \
|
||||
/*printf("memcpy(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
|
||||
memcpy(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
|
||||
|
||||
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_t) \
|
||||
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t));*/ \
|
||||
memmove(dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t)); \
|
||||
memcpy(dest + beg, slice, slice_len * sizeof(item_t));
|
||||
|
||||
@@ -1,3 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -10,19 +37,22 @@
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
|
||||
typedef struct _mp_obj_array_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t typecode : 8;
|
||||
mp_uint_t typecode : 8;
|
||||
// free is number of unused elements after len used elements
|
||||
// alloc size = len + free
|
||||
machine_uint_t free : (8 * sizeof(machine_uint_t) - 8);
|
||||
machine_uint_t len; // in elements
|
||||
mp_uint_t free : (8 * sizeof(mp_uint_t) - 8);
|
||||
mp_uint_t len; // in elements
|
||||
void *items;
|
||||
} mp_obj_array_t;
|
||||
|
||||
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
|
||||
STATIC mp_obj_array_t *array_new(char typecode, uint n);
|
||||
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
|
||||
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
/******************************************************************************/
|
||||
/* array */
|
||||
@@ -30,8 +60,8 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
|
||||
STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_array_t *o = o_in;
|
||||
if (o->typecode == BYTEARRAY_TYPECODE) {
|
||||
print(env, "bytearray(b", o->typecode);
|
||||
mp_str_print_quoted(print, env, o->items, o->len);
|
||||
print(env, "bytearray(b");
|
||||
mp_str_print_quoted(print, env, o->items, o->len, true);
|
||||
} else {
|
||||
print(env, "array('%c'", o->typecode);
|
||||
if (o->len > 0) {
|
||||
@@ -113,7 +143,23 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_EQUAL: {
|
||||
mp_buffer_info_t lhs_bufinfo;
|
||||
mp_buffer_info_t rhs_bufinfo;
|
||||
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
|
||||
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
|
||||
}
|
||||
default:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,26 +185,30 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
|
||||
// TODO implement
|
||||
// TODO: confirmed that both bytearray and array.array support
|
||||
// slice deletion
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
} else {
|
||||
mp_obj_array_t *o = self_in;
|
||||
if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
|
||||
if (0) {
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
} else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
|
||||
if (value != MP_OBJ_SENTINEL) {
|
||||
// Only getting a slice is suported so far, not assignment
|
||||
// TODO: confirmed that both bytearray and array.array support
|
||||
// slice assignment (incl. of different size)
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
machine_uint_t start, stop;
|
||||
if (!m_seq_get_fast_slice_indexes(o->len, index_in, &start, &stop)) {
|
||||
assert(0);
|
||||
mp_bound_slice_t slice;
|
||||
if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
"only slices with step=1 (aka None) are supported"));
|
||||
}
|
||||
mp_obj_array_t *res = array_new(o->typecode, stop - start);
|
||||
mp_obj_array_t *res = array_new(o->typecode, slice.stop - slice.start);
|
||||
int sz = mp_binary_get_size('@', o->typecode, NULL);
|
||||
assert(sz > 0);
|
||||
byte *p = o->items;
|
||||
memcpy(res->items, p + start * sz, (stop - start) * sz);
|
||||
memcpy(res->items, p + slice.start * sz, (slice.stop - slice.start) * sz);
|
||||
return res;
|
||||
#endif
|
||||
} else {
|
||||
uint index = mp_get_index(o->base.type, o->len, index_in, false);
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
@@ -173,7 +223,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
|
||||
}
|
||||
}
|
||||
|
||||
STATIC machine_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
|
||||
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
|
||||
mp_obj_array_t *o = o_in;
|
||||
bufinfo->buf = o->items;
|
||||
bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
|
||||
@@ -194,6 +244,7 @@ const mp_obj_type_t mp_type_array = {
|
||||
.make_new = array_make_new,
|
||||
.getiter = array_iterator_new,
|
||||
.unary_op = array_unary_op,
|
||||
.binary_op = array_binary_op,
|
||||
.subscr = array_subscr,
|
||||
.buffer_p = { .get_buffer = array_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&array_locals_dict,
|
||||
@@ -206,6 +257,7 @@ const mp_obj_type_t mp_type_bytearray = {
|
||||
.make_new = bytearray_make_new,
|
||||
.getiter = array_iterator_new,
|
||||
.unary_op = array_unary_op,
|
||||
.binary_op = array_binary_op,
|
||||
.subscr = array_subscr,
|
||||
.buffer_p = { .get_buffer = array_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&array_locals_dict,
|
||||
@@ -252,7 +304,7 @@ mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) {
|
||||
typedef struct _mp_obj_array_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_array_t *array;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_array_it_t;
|
||||
|
||||
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
|
||||
@@ -279,3 +331,5 @@ STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
|
||||
o->cur = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
|
||||
@@ -1 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_obj_new_bytearray(uint n, void *items);
|
||||
|
||||
42
py/objbool.c
42
py/objbool.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
@@ -23,17 +49,19 @@ STATIC void bool_print(void (*print)(void *env, const char *fmt, ...), void *env
|
||||
}
|
||||
|
||||
STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
// TODO check n_kw == 0
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
|
||||
switch (n_args) {
|
||||
case 0: return mp_const_false;
|
||||
case 1: if (mp_obj_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
|
||||
default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bool takes at most 1 argument, %d given", n_args));
|
||||
case 0:
|
||||
return mp_const_false;
|
||||
case 1:
|
||||
default: // must be 0 or 1
|
||||
if (mp_obj_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
|
||||
machine_int_t value = ((mp_obj_bool_t*)o_in)->value;
|
||||
mp_int_t value = ((mp_obj_bool_t*)o_in)->value;
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return o_in;
|
||||
case MP_UNARY_OP_POSITIVE: return MP_OBJ_NEW_SMALL_INT(value);
|
||||
@@ -46,9 +74,9 @@ STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
|
||||
|
||||
STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
|
||||
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in);
|
||||
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(mp_obj_is_true(lhs_in)), rhs_in);
|
||||
}
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_bool = {
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
@@ -13,6 +39,17 @@ typedef struct _mp_obj_bound_meth_t {
|
||||
mp_obj_t self;
|
||||
} mp_obj_bound_meth_t;
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
|
||||
STATIC void bound_meth_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_bound_meth_t *o = o_in;
|
||||
print(env, "<bound_method %p ", o);
|
||||
mp_obj_print_helper(print, env, o->self, PRINT_REPR);
|
||||
print(env, ".");
|
||||
mp_obj_print_helper(print, env, o->meth, PRINT_REPR);
|
||||
print(env, ">");
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t bound_meth_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_bound_meth_t *self = self_in;
|
||||
|
||||
@@ -39,6 +76,9 @@ mp_obj_t bound_meth_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_
|
||||
const mp_obj_type_t bound_meth_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_bound_method,
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
|
||||
.print = bound_meth_print,
|
||||
#endif
|
||||
.call = bound_meth_call,
|
||||
};
|
||||
|
||||
|
||||
26
py/objcell.c
26
py/objcell.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
@@ -11,7 +37,7 @@
|
||||
typedef struct _mp_obj_closure_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t fun;
|
||||
machine_uint_t n_closed;
|
||||
mp_uint_t n_closed;
|
||||
mp_obj_t closed[];
|
||||
} mp_obj_closure_t;
|
||||
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -8,8 +34,9 @@
|
||||
#include "obj.h"
|
||||
#include "parsenum.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -48,7 +75,7 @@ STATIC void complex_print(void (*print)(void *env, const char *fmt, ...), void *
|
||||
}
|
||||
|
||||
STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
// TODO check n_kw == 0
|
||||
mp_arg_check_num(n_args, n_kw, 0, 2, false);
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
@@ -68,7 +95,8 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
|
||||
return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);
|
||||
}
|
||||
|
||||
case 2: {
|
||||
case 2:
|
||||
default: {
|
||||
mp_float_t real, imag;
|
||||
if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) {
|
||||
mp_obj_complex_get(args[0], &real, &imag);
|
||||
@@ -86,9 +114,6 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
|
||||
}
|
||||
return mp_obj_new_complex(real, imag);
|
||||
}
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "complex takes at most 2 arguments, %d given", n_args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +123,7 @@ STATIC mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(o->real != 0 || o->imag != 0);
|
||||
case MP_UNARY_OP_POSITIVE: return o_in;
|
||||
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +132,15 @@ STATIC mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
|
||||
}
|
||||
|
||||
STATIC void complex_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_complex_t *self = self_in;
|
||||
if (attr == MP_QSTR_real) {
|
||||
dest[0] = mp_obj_new_float(self->real);
|
||||
} else if (attr == MP_QSTR_imag) {
|
||||
dest[0] = mp_obj_new_float(self->imag);
|
||||
}
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_complex = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_complex,
|
||||
@@ -114,6 +148,7 @@ const mp_obj_type_t mp_type_complex = {
|
||||
.make_new = complex_make_new,
|
||||
.unary_op = complex_unary_op,
|
||||
.binary_op = complex_binary_op,
|
||||
.load_attr = complex_load_attr,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {
|
||||
@@ -208,7 +243,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
|
||||
case MP_BINARY_OP_EQUAL: return MP_BOOL(lhs_real == rhs_real && lhs_imag == rhs_imag);
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
return mp_obj_new_complex(lhs_real, lhs_imag);
|
||||
}
|
||||
|
||||
169
py/objdict.c
169
py/objdict.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@@ -14,7 +40,7 @@
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur);
|
||||
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in);
|
||||
STATIC mp_obj_t dict_copy(mp_obj_t self_in);
|
||||
STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs);
|
||||
|
||||
STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_dict_t *self = self_in;
|
||||
@@ -35,40 +61,13 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
|
||||
}
|
||||
|
||||
STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_t dict;
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
dict = mp_obj_new_dict(0);
|
||||
break;
|
||||
|
||||
case 1: {
|
||||
if (MP_OBJ_IS_TYPE(args[0], &mp_type_dict)) {
|
||||
return dict_copy(args[0]);
|
||||
}
|
||||
// TODO create dict from an arbitrary mapping!
|
||||
|
||||
// Make dict from iterable of pairs
|
||||
mp_obj_t iterable = mp_getiter(args[0]);
|
||||
mp_obj_t dict = mp_obj_new_dict(0);
|
||||
// TODO: support arbitrary seq as a pair
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_obj_t *sub_items;
|
||||
mp_obj_get_array_fixed_n(item, 2, &sub_items);
|
||||
mp_obj_dict_store(dict, sub_items[0], sub_items[1]);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "dict takes at most 1 argument"));
|
||||
mp_obj_t dict = mp_obj_new_dict(0);
|
||||
if (n_args > 0 || n_kw > 0) {
|
||||
mp_obj_t args2[2] = {dict, args[0]}; // args[0] is always valid, even if it's not a positional arg
|
||||
mp_map_t kwargs;
|
||||
mp_map_init_fixed_table(&kwargs, n_kw, args + n_args);
|
||||
dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2
|
||||
}
|
||||
|
||||
// add to the new dict any keyword args
|
||||
for (const mp_obj_t *a = args + n_args; n_kw > 0; n_kw--, a += 2) {
|
||||
mp_obj_dict_store(dict, a[0], a[1]);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
@@ -76,8 +75,8 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
|
||||
mp_obj_dict_t *self = self_in;
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->map.used);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->map.used);
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,10 +94,10 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
machine_uint_t size = o->map.alloc;
|
||||
mp_uint_t size = o->map.alloc;
|
||||
mp_map_t *map = &o->map;
|
||||
|
||||
for (machine_uint_t i = 0; i < size; i++) {
|
||||
for (mp_uint_t i = 0; i < size; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
|
||||
mp_map_elem_t *elem = mp_map_lookup(&rhs->map, map->table[i].key, MP_MAP_LOOKUP);
|
||||
if (elem == NULL || !mp_obj_equal(map->table[i].value, elem->value)) {
|
||||
@@ -114,7 +113,18 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
}
|
||||
default:
|
||||
// op not supported
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make sure this is inlined in dict_subscr() below.
|
||||
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) {
|
||||
mp_obj_dict_t *self = self_in;
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
|
||||
if (elem == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>"));
|
||||
} else {
|
||||
return elem->value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,12 +155,12 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
typedef struct _mp_obj_dict_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *dict;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_dict_it_t;
|
||||
|
||||
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) {
|
||||
mp_obj_dict_it_t *self = self_in;
|
||||
machine_uint_t max = self->dict->map.alloc;
|
||||
mp_uint_t max = self->dict->map.alloc;
|
||||
mp_map_t *map = &self->dict->map;
|
||||
|
||||
for (int i = self->cur; i < max; i++) {
|
||||
@@ -322,31 +332,57 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
|
||||
|
||||
STATIC mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict));
|
||||
mp_obj_dict_t *self = self_in;
|
||||
/* TODO: check for the "keys" method */
|
||||
mp_obj_t iter = mp_getiter(iterable);
|
||||
mp_obj_t next = NULL;
|
||||
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_obj_t inneriter = mp_getiter(next);
|
||||
mp_obj_t key = mp_iternext(inneriter);
|
||||
mp_obj_t value = mp_iternext(inneriter);
|
||||
mp_obj_t stop = mp_iternext(inneriter);
|
||||
if (key == MP_OBJ_STOP_ITERATION
|
||||
|| value == MP_OBJ_STOP_ITERATION
|
||||
|| stop != MP_OBJ_STOP_ITERATION) {
|
||||
nlr_raise(mp_obj_new_exception_msg(
|
||||
&mp_type_ValueError,
|
||||
"dictionary update sequence has the wrong length"));
|
||||
STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
assert(MP_OBJ_IS_TYPE(args[0], &mp_type_dict));
|
||||
mp_obj_dict_t *self = args[0];
|
||||
|
||||
mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
|
||||
|
||||
if (n_args == 2) {
|
||||
// given a positional argument
|
||||
|
||||
if (MP_OBJ_IS_TYPE(args[1], &mp_type_dict)) {
|
||||
// update from other dictionary (make sure other is not self)
|
||||
if (args[1] != self) {
|
||||
// TODO don't allocate heap object for this iterator
|
||||
mp_obj_t *dict_iter = mp_obj_new_dict_iterator(args[1], 0);
|
||||
mp_map_elem_t *elem = NULL;
|
||||
while ((elem = dict_it_iternext_elem(dict_iter)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
||||
// update from a generic iterable of pairs
|
||||
mp_obj_t iter = mp_getiter(args[1]);
|
||||
mp_obj_t next = NULL;
|
||||
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_obj_t inneriter = mp_getiter(next);
|
||||
mp_obj_t key = mp_iternext(inneriter);
|
||||
mp_obj_t value = mp_iternext(inneriter);
|
||||
mp_obj_t stop = mp_iternext(inneriter);
|
||||
if (key == MP_OBJ_STOP_ITERATION
|
||||
|| value == MP_OBJ_STOP_ITERATION
|
||||
|| stop != MP_OBJ_STOP_ITERATION) {
|
||||
nlr_raise(mp_obj_new_exception_msg(
|
||||
&mp_type_ValueError,
|
||||
"dictionary update sequence has the wrong length"));
|
||||
} else {
|
||||
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update the dict with any keyword args
|
||||
for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
|
||||
mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(dict_update_obj, dict_update);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -367,7 +403,7 @@ typedef struct _mp_obj_dict_view_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_dict_view_kind_t kind;
|
||||
mp_obj_dict_it_t *iter;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_dict_view_it_t;
|
||||
|
||||
typedef struct _mp_obj_dict_view_t {
|
||||
@@ -437,14 +473,17 @@ STATIC void dict_view_print(void (*print)(void *env, const char *fmt, ...), void
|
||||
}
|
||||
|
||||
STATIC mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
/* only supported for the 'keys' kind until sets and dicts are refactored */
|
||||
// only supported for the 'keys' kind until sets and dicts are refactored
|
||||
mp_obj_dict_view_t *o = lhs_in;
|
||||
if (o->kind != MP_DICT_VIEW_KEYS) return NULL;
|
||||
if (op != MP_BINARY_OP_IN) return NULL;
|
||||
if (o->kind != MP_DICT_VIEW_KEYS) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
if (op != MP_BINARY_OP_IN) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
return dict_binary_op(op, o->dict, rhs_in);
|
||||
}
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t dict_view_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_dict_view,
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -10,19 +36,35 @@
|
||||
typedef struct _mp_obj_enumerate_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t iter;
|
||||
machine_int_t cur;
|
||||
mp_int_t cur;
|
||||
} mp_obj_enumerate_t;
|
||||
|
||||
STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in);
|
||||
|
||||
/* TODO: enumerate is one of the ones that can take args or kwargs.
|
||||
Sticking to args for now */
|
||||
STATIC const mp_arg_t enumerate_make_new_args[] = {
|
||||
{ MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_start, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
#define ENUMERATE_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(enumerate_make_new_args)
|
||||
|
||||
STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
assert(n_args > 0);
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
// parse args
|
||||
mp_arg_val_t vals[ENUMERATE_MAKE_NEW_NUM_ARGS];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, args, ENUMERATE_MAKE_NEW_NUM_ARGS, enumerate_make_new_args, vals);
|
||||
|
||||
// create enumerate object
|
||||
mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);
|
||||
o->base.type = &mp_type_enumerate;
|
||||
o->iter = mp_getiter(vals[0].u_obj);
|
||||
o->cur = vals[1].u_int;
|
||||
#else
|
||||
mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);
|
||||
o->base.type = &mp_type_enumerate;
|
||||
o->iter = mp_getiter(args[0]);
|
||||
o->cur = n_args > 1 ? mp_obj_get_int(args[1]) : 0;
|
||||
#endif
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
180
py/objexcept.c
180
py/objexcept.c
@@ -1,16 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "objstr.h"
|
||||
#include "objtuple.h"
|
||||
#include "objtype.h"
|
||||
#include "runtime.h"
|
||||
#include "runtime0.h"
|
||||
#include "gc.h"
|
||||
|
||||
typedef struct _mp_obj_exception_t {
|
||||
mp_obj_base_t base;
|
||||
@@ -24,6 +54,53 @@ const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_
|
||||
// Local non-heap memory for allocating an exception when we run out of RAM
|
||||
STATIC mp_obj_exception_t mp_emergency_exception_obj;
|
||||
|
||||
// Optionally allocated buffer for storing the first argument of an exception
|
||||
// allocated when the heap is locked.
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
|
||||
STATIC byte mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE];
|
||||
#define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
|
||||
|
||||
void mp_init_emergency_exception_buf(void) {
|
||||
// Nothing to do since the buffer was declared statically. We put this
|
||||
// definition here so that the calling code can call this function
|
||||
// regardless of how its configured (makes the calling code a bit cleaner).
|
||||
}
|
||||
|
||||
#else
|
||||
STATIC mp_int_t mp_emergency_exception_buf_size = 0;
|
||||
STATIC byte *mp_emergency_exception_buf = NULL;
|
||||
|
||||
void mp_init_emergency_exception_buf(void) {
|
||||
mp_emergency_exception_buf_size = 0;
|
||||
mp_emergency_exception_buf = NULL;
|
||||
}
|
||||
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
|
||||
mp_int_t size = mp_obj_get_int(size_in);
|
||||
void *buf = NULL;
|
||||
if (size > 0) {
|
||||
buf = m_malloc(size);
|
||||
}
|
||||
|
||||
int old_size = mp_emergency_exception_buf_size;
|
||||
void *old_buf = mp_emergency_exception_buf;
|
||||
|
||||
// Update the 2 variables atomically so that an interrupt can't occur
|
||||
// between the assignments.
|
||||
mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
mp_emergency_exception_buf_size = size;
|
||||
mp_emergency_exception_buf = buf;
|
||||
MICROPY_END_ATOMIC_SECTION(irq_state);
|
||||
|
||||
if (old_buf != NULL) {
|
||||
m_free(old_buf, old_size);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
|
||||
// Instance of GeneratorExit exception - needed by generator.close()
|
||||
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
|
||||
// definition module-private so far, have it here.
|
||||
@@ -50,7 +127,7 @@ STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...
|
||||
return;
|
||||
}
|
||||
}
|
||||
tuple_print(print, env, o->args, kind);
|
||||
mp_obj_tuple_print(print, env, o->args, kind);
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
@@ -94,12 +171,27 @@ STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t exc___init__(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_exception_t *self = args[0];
|
||||
mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1);
|
||||
self->args = argst;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__);
|
||||
|
||||
STATIC const mp_map_elem_t exc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&exc___init___obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t mp_type_BaseException = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_BaseException,
|
||||
.print = mp_obj_exception_print,
|
||||
.make_new = mp_obj_exception_make_new,
|
||||
.load_attr = exception_load_attr,
|
||||
.locals_dict = (mp_obj_t)&exc_locals_dict,
|
||||
};
|
||||
|
||||
#define MP_DEFINE_EXCEPTION_BASE(base_name) \
|
||||
@@ -116,9 +208,9 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
|
||||
};
|
||||
|
||||
// List of all exceptions, arranged as in the table at:
|
||||
// http://docs.python.org/3.3/library/exceptions.html
|
||||
// http://docs.python.org/3/library/exceptions.html
|
||||
MP_DEFINE_EXCEPTION_BASE(BaseException)
|
||||
//MP_DEFINE_EXCEPTION(SystemExit, BaseException)
|
||||
MP_DEFINE_EXCEPTION(SystemExit, BaseException)
|
||||
//MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
|
||||
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
|
||||
MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
@@ -142,11 +234,13 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
MP_DEFINE_EXCEPTION(KeyError, LookupError)
|
||||
MP_DEFINE_EXCEPTION(MemoryError, Exception)
|
||||
MP_DEFINE_EXCEPTION(NameError, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(NameError)
|
||||
//MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
|
||||
MP_DEFINE_EXCEPTION(OSError, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(OSError)
|
||||
/*
|
||||
MP_DEFINE_EXCEPTION_BASE(NameError)
|
||||
MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
|
||||
*/
|
||||
MP_DEFINE_EXCEPTION(OSError, Exception)
|
||||
/*
|
||||
MP_DEFINE_EXCEPTION_BASE(OSError)
|
||||
MP_DEFINE_EXCEPTION(BlockingIOError, OSError)
|
||||
MP_DEFINE_EXCEPTION(ChildProcessError, OSError)
|
||||
MP_DEFINE_EXCEPTION(ConnectionError, OSError)
|
||||
@@ -224,6 +318,50 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
o->args = mp_const_empty_tuple;
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
// If the user has provided a buffer, then we try to create a tuple
|
||||
// of length 1, which has a string object and the string data.
|
||||
|
||||
if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) {
|
||||
mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_emergency_exception_buf;
|
||||
mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1];
|
||||
|
||||
tuple->base.type = &mp_type_tuple;
|
||||
tuple->len = 1;
|
||||
tuple->items[0] = str;
|
||||
|
||||
byte *str_data = (byte *)&str[1];
|
||||
uint max_len = mp_emergency_exception_buf + mp_emergency_exception_buf_size
|
||||
- str_data;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
str->len = vsnprintf((char *)str_data, max_len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
str->base.type = &mp_type_str;
|
||||
str->hash = qstr_compute_hash(str_data, str->len);
|
||||
str->data = str_data;
|
||||
|
||||
o->args = tuple;
|
||||
|
||||
uint offset = &str_data[str->len] - mp_emergency_exception_buf;
|
||||
offset += sizeof(void *) - 1;
|
||||
offset &= ~(sizeof(void *) - 1);
|
||||
|
||||
if ((mp_emergency_exception_buf_size - offset) > (sizeof(mp_obj_list_t) + sizeof(mp_obj_t) * 3)) {
|
||||
// We have room to store some traceback.
|
||||
mp_obj_list_t *list = (mp_obj_list_t *)((byte *)mp_emergency_exception_buf + offset);
|
||||
list->base.type = &mp_type_list;
|
||||
list->items = (mp_obj_t)&list[1];
|
||||
list->alloc = (mp_emergency_exception_buf + mp_emergency_exception_buf_size - (byte *)list->items) / sizeof(list->items[0]);
|
||||
list->len = 0;
|
||||
|
||||
o->traceback = list;
|
||||
}
|
||||
}
|
||||
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
} else {
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
@@ -240,7 +378,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
va_start(ap, fmt);
|
||||
vstr_vprintf(vstr, fmt, ap);
|
||||
va_end(ap);
|
||||
o->args->items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
|
||||
o->args->items[0] = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
}
|
||||
}
|
||||
@@ -291,19 +429,35 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
|
||||
self->traceback = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) {
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block) {
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
if (gc_is_locked()) {
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
// We can't allocate any memory, and no memory has been
|
||||
// pre-allocated, so there is nothing else we can do.
|
||||
return;
|
||||
}
|
||||
mp_obj_list_t *list = self->traceback;
|
||||
if (list->alloc <= (list->len + 3)) {
|
||||
// There is some preallocated memory, but not enough to store an
|
||||
// entire record.
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// for traceback, we are just using the list object for convenience, it's not really a list of Python objects
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
self->traceback = mp_obj_new_list(0, NULL);
|
||||
}
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)file);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)line);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)block);
|
||||
}
|
||||
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) {
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values) {
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -11,8 +37,9 @@
|
||||
#include "obj.h"
|
||||
#include "parsenum.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
#include "formatfloat.h"
|
||||
@@ -40,13 +67,14 @@ STATIC void float_print(void (*print)(void *env, const char *fmt, ...), void *en
|
||||
}
|
||||
|
||||
STATIC mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
// TODO check n_kw == 0
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
return mp_obj_new_float(0);
|
||||
|
||||
case 1:
|
||||
default:
|
||||
if (MP_OBJ_IS_STR(args[0])) {
|
||||
// a string, parse it
|
||||
uint l;
|
||||
@@ -59,9 +87,6 @@ STATIC mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
|
||||
// something else, try to cast it to a float
|
||||
return mp_obj_new_float(mp_obj_get_float(args[0]));
|
||||
}
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "float takes at most 1 argument, %d given", n_args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,15 +96,18 @@ STATIC mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(o->value != 0);
|
||||
case MP_UNARY_OP_POSITIVE: return o_in;
|
||||
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-o->value);
|
||||
default: return NULL; // op not supported
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t float_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_obj_float_t *lhs = lhs_in;
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
|
||||
return mp_obj_complex_binary_op(op, lhs->value, 0, rhs_in);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return mp_obj_float_binary_op(op, lhs->value, rhs_in);
|
||||
}
|
||||
}
|
||||
@@ -140,9 +168,9 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) {
|
||||
case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val);
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
return mp_obj_new_float(lhs_val);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_FLOAT
|
||||
#endif // MICROPY_PY_BUILTINS_FLOAT
|
||||
|
||||
558
py/objfun.c
558
py/objfun.c
@@ -1,7 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
@@ -13,6 +39,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "bc.h"
|
||||
#include "stackctrl.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -20,24 +47,26 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* native functions */
|
||||
|
||||
// mp_obj_fun_native_t defined in obj.h
|
||||
|
||||
STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
// This binary_op method is used for all function types, and is also
|
||||
// used to determine if an object is of generic function type.
|
||||
mp_obj_t mp_obj_fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_EQUAL:
|
||||
// These objects can be equal only if it's the same underlying structure,
|
||||
// we don't even need to check for 2nd arg type.
|
||||
return MP_BOOL(lhs_in == rhs_in);
|
||||
}
|
||||
return NULL;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native));
|
||||
mp_obj_fun_native_t *self = self_in;
|
||||
/******************************************************************************/
|
||||
/* builtin functions */
|
||||
|
||||
// mp_obj_fun_builtin_t defined in obj.h
|
||||
|
||||
STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin));
|
||||
mp_obj_fun_builtin_t *self = self_in;
|
||||
|
||||
// check number of arguments
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw);
|
||||
@@ -80,26 +109,16 @@ STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const
|
||||
}
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_fun_native = {
|
||||
const mp_obj_type_t mp_type_fun_builtin = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_native_call,
|
||||
.binary_op = fun_binary_op,
|
||||
.call = fun_builtin_call,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
// fun must have the correct signature for n_args fixed arguments
|
||||
mp_obj_t mp_make_function_n(int n_args, void *fun) {
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->is_kw = false;
|
||||
o->n_args_min = n_args;
|
||||
o->n_args_max = n_args;
|
||||
o->fun = fun;
|
||||
return o;
|
||||
}
|
||||
|
||||
#if 0 // currently unused, and semi-obsolete
|
||||
mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
mp_obj_fun_builtin_t *o = m_new_obj(mp_obj_fun_builtin_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->is_kw = false;
|
||||
o->n_args_min = n_args_min;
|
||||
@@ -110,7 +129,7 @@ mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
|
||||
|
||||
// min and max are inclusive
|
||||
mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
mp_obj_fun_builtin_t *o = m_new_obj(mp_obj_fun_builtin_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->is_kw = false;
|
||||
o->n_args_min = n_args_min;
|
||||
@@ -118,6 +137,7 @@ mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var
|
||||
o->fun = fun;
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* byte code functions */
|
||||
@@ -127,8 +147,8 @@ const char *mp_obj_code_get_name(const byte *code_info) {
|
||||
return qstr_str(block_name);
|
||||
}
|
||||
|
||||
const char *mp_obj_fun_get_name(mp_obj_t fun_in) {
|
||||
mp_obj_fun_bc_t *fun = fun_in;
|
||||
const char *mp_obj_fun_get_name(mp_const_obj_t fun_in) {
|
||||
const mp_obj_fun_bc_t *fun = fun_in;
|
||||
const byte *code_info = fun->bytecode;
|
||||
return mp_obj_code_get_name(code_info);
|
||||
}
|
||||
@@ -152,7 +172,7 @@ STATIC void dump_args(const mp_obj_t *a, int sz) {
|
||||
#define dump_args(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, uint given) {
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
// Generic message, to be reused for other argument issues
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
@@ -167,66 +187,34 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, ui
|
||||
#endif
|
||||
}
|
||||
|
||||
// If it's possible to call a function without allocating new argument array,
|
||||
// this function returns true, together with pointers to 2 subarrays to be used
|
||||
// as arguments. Otherwise, it returns false. It is expected that this fucntion
|
||||
// will be accompanied by another, mp_obj_fun_prepare_full_args(), which will
|
||||
// instead take pointer to full-length out-array, and will fill it in. Rationale
|
||||
// being that a caller can try this function and if it succeeds, the function call
|
||||
// can be made without allocating extra memory. Otherwise, caller can allocate memory
|
||||
// and try "full" function. These functions are expected to be refactoring of
|
||||
// code in fun_bc_call() and evenrually replace it.
|
||||
bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
|
||||
uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2) {
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
DEBUG_printf("mp_obj_fun_prepare_simple_args: given: %d pos, %d kw, expected: %d pos (%d default)\n",
|
||||
n_args, n_kw, self->n_pos_args, self->n_def_args);
|
||||
// With this macro you can tune the maximum number of function state bytes
|
||||
// that will be allocated on the stack. Any function that needs more
|
||||
// than this will use the heap.
|
||||
#define VM_MAX_STATE_ON_STACK (10 * sizeof(mp_uint_t))
|
||||
|
||||
assert(n_kw == 0);
|
||||
assert(self->n_kwonly_args == 0);
|
||||
assert(self->takes_var_args == 0);
|
||||
assert(self->takes_kw_args == 0);
|
||||
// Set this to enable a simple stack overflow check.
|
||||
#define VM_DETECT_STACK_OVERFLOW (0)
|
||||
|
||||
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
|
||||
uint n_extra_args = 0;
|
||||
|
||||
if (n_args > self->n_pos_args) {
|
||||
goto arg_error;
|
||||
} else {
|
||||
if (n_args >= self->n_pos_args - self->n_def_args) {
|
||||
extra_args -= self->n_pos_args - n_args;
|
||||
n_extra_args += self->n_pos_args - n_args;
|
||||
} else {
|
||||
fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
|
||||
}
|
||||
}
|
||||
*out_args1 = args;
|
||||
*out_args1_len = n_args;
|
||||
*out_args2 = extra_args;
|
||||
*out_args2_len = n_extra_args;
|
||||
return true;
|
||||
|
||||
arg_error:
|
||||
fun_pos_args_mismatch(self, self->n_pos_args, n_args);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
// code_state should have ->ip filled in (pointing past code info block),
|
||||
// as well as ->n_state.
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
|
||||
// usage for the common case of positional only args.
|
||||
//
|
||||
// extra_args layout: def_args, var_arg tuple, kwonly args, var_kw dict
|
||||
|
||||
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
|
||||
DEBUG_printf("Input pos args: ");
|
||||
dump_args(args, n_args);
|
||||
DEBUG_printf("Input kw args: ");
|
||||
dump_args(args + n_args, n_kw * 2);
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
|
||||
mp_uint_t n_state = code_state->n_state;
|
||||
const byte *ip = code_state->ip;
|
||||
|
||||
code_state->code_info = self->bytecode;
|
||||
code_state->sp = &code_state->state[0] - 1;
|
||||
code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
|
||||
|
||||
// zero out the local stack to begin with
|
||||
memset(code_state->state, 0, n_state * sizeof(*code_state->state));
|
||||
|
||||
const mp_obj_t *kwargs = args + n_args;
|
||||
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
|
||||
uint n_extra_args = 0;
|
||||
|
||||
// var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
|
||||
mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - self->n_pos_args - self->n_kwonly_args];
|
||||
|
||||
// check positional arguments
|
||||
|
||||
@@ -236,57 +224,53 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
||||
fun_pos_args_mismatch(self, self->n_pos_args, n_args);
|
||||
}
|
||||
// put extra arguments in varargs tuple
|
||||
*extra_args = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
|
||||
n_extra_args = 1;
|
||||
*var_pos_kw_args-- = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
|
||||
n_args = self->n_pos_args;
|
||||
} else {
|
||||
if (self->takes_var_args) {
|
||||
DEBUG_printf("passing empty tuple as *args\n");
|
||||
*extra_args = mp_const_empty_tuple;
|
||||
n_extra_args = 1;
|
||||
*var_pos_kw_args-- = mp_const_empty_tuple;
|
||||
}
|
||||
// Apply processing and check below only if we don't have kwargs,
|
||||
// otherwise, kw handling code below has own extensive checks.
|
||||
if (n_kw == 0) {
|
||||
if (n_kw == 0 && !self->has_def_kw_args) {
|
||||
if (n_args >= self->n_pos_args - self->n_def_args) {
|
||||
// given enough arguments, but may need to use some default arguments
|
||||
extra_args -= self->n_pos_args - n_args;
|
||||
n_extra_args += self->n_pos_args - n_args;
|
||||
for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
|
||||
code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
|
||||
}
|
||||
} else {
|
||||
fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy positional args into state
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
code_state->state[n_state - 1 - i] = args[i];
|
||||
}
|
||||
|
||||
// check keyword arguments
|
||||
|
||||
if (n_kw != 0) {
|
||||
// We cannot use dynamically-sized array here, because GCC indeed
|
||||
// deallocates it on leaving defining scope (unlike most static stack allocs).
|
||||
// So, we have 2 choices: allocate it unconditionally at the top of function
|
||||
// (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
|
||||
//mp_obj_t flat_args[self->n_args];
|
||||
mp_obj_t *flat_args = alloca((self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t));
|
||||
for (int i = self->n_pos_args + self->n_kwonly_args - 1; i >= 0; i--) {
|
||||
flat_args[i] = MP_OBJ_NULL;
|
||||
}
|
||||
memcpy(flat_args, args, sizeof(*args) * n_args);
|
||||
if (n_kw != 0 || self->has_def_kw_args) {
|
||||
DEBUG_printf("Initial args: ");
|
||||
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
|
||||
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
|
||||
|
||||
mp_obj_t dict = MP_OBJ_NULL;
|
||||
if (self->takes_kw_args) {
|
||||
dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
|
||||
*var_pos_kw_args = dict;
|
||||
}
|
||||
for (uint i = 0; i < n_kw; i++) {
|
||||
|
||||
for (mp_uint_t i = 0; i < n_kw; i++) {
|
||||
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
||||
for (uint j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||
if (arg_name == self->args[j]) {
|
||||
if (flat_args[j] != MP_OBJ_NULL) {
|
||||
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function got multiple values for argument '%s'", qstr_str(arg_name)));
|
||||
}
|
||||
flat_args[j] = kwargs[2 * i + 1];
|
||||
code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
|
||||
goto continue2;
|
||||
}
|
||||
}
|
||||
@@ -297,43 +281,47 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
||||
mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
|
||||
continue2:;
|
||||
}
|
||||
DEBUG_printf("Args with kws flattened: ");
|
||||
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
|
||||
|
||||
// Now fill in defaults for positional args
|
||||
mp_obj_t *d = &flat_args[self->n_pos_args - 1];
|
||||
DEBUG_printf("Args with kws flattened: ");
|
||||
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
|
||||
|
||||
// fill in defaults for positional args
|
||||
mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
|
||||
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
|
||||
for (int i = self->n_def_args; i > 0; i--, d--, s--) {
|
||||
for (int i = self->n_def_args; i > 0; i--, d++, s--) {
|
||||
if (*d == MP_OBJ_NULL) {
|
||||
*d = *s;
|
||||
}
|
||||
}
|
||||
DEBUG_printf("Args after filling defaults: ");
|
||||
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
|
||||
|
||||
DEBUG_printf("Args after filling default positional: ");
|
||||
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
|
||||
|
||||
// Check that all mandatory positional args are specified
|
||||
while (d >= flat_args) {
|
||||
if (*d-- == MP_OBJ_NULL) {
|
||||
while (d < &code_state->state[n_state]) {
|
||||
if (*d++ == MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function missing required positional argument #%d", d - flat_args));
|
||||
"function missing required positional argument #%d", &code_state->state[n_state] - d));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all mandatory keyword args are specified
|
||||
for (int i = 0; i < self->n_kwonly_args; i++) {
|
||||
if (flat_args[self->n_pos_args + i] == MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
|
||||
// Fill in default kw args if we have them
|
||||
for (mp_uint_t i = 0; i < self->n_kwonly_args; i++) {
|
||||
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if (self->has_def_kw_args) {
|
||||
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP);
|
||||
}
|
||||
if (elem != NULL) {
|
||||
code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args = flat_args;
|
||||
n_args = self->n_pos_args + self->n_kwonly_args;
|
||||
|
||||
if (self->takes_kw_args) {
|
||||
extra_args[n_extra_args] = dict;
|
||||
n_extra_args += 1;
|
||||
}
|
||||
} else {
|
||||
// no keyword arguments given
|
||||
if (self->n_kwonly_args != 0) {
|
||||
@@ -341,20 +329,121 @@ continue2:;
|
||||
"function missing keyword-only argument"));
|
||||
}
|
||||
if (self->takes_kw_args) {
|
||||
extra_args[n_extra_args] = mp_obj_new_dict(0);
|
||||
n_extra_args += 1;
|
||||
*var_pos_kw_args = mp_obj_new_dict(0);
|
||||
}
|
||||
}
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
|
||||
mp_uint_t local_num = *ip++;
|
||||
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
|
||||
}
|
||||
|
||||
// now that we skipped over the prelude, set the ip for the VM
|
||||
code_state->ip = ip;
|
||||
|
||||
DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", self->n_pos_args, self->n_kwonly_args);
|
||||
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
|
||||
dump_args(code_state->state, n_state);
|
||||
}
|
||||
|
||||
|
||||
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
MP_STACK_CHECK();
|
||||
|
||||
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
|
||||
DEBUG_printf("Input pos args: ");
|
||||
dump_args(args, n_args);
|
||||
DEBUG_printf("Input kw args: ");
|
||||
dump_args(args + n_args, n_kw * 2);
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
|
||||
|
||||
const byte *ip = self->bytecode;
|
||||
|
||||
// get code info size, and skip line number table
|
||||
mp_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
|
||||
ip += code_info_size;
|
||||
|
||||
// bytecode prelude: state size and exception stack size; 16 bit uints
|
||||
mp_uint_t n_state = ip[0] | (ip[1] << 8);
|
||||
mp_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
|
||||
ip += 4;
|
||||
|
||||
#if VM_DETECT_STACK_OVERFLOW
|
||||
n_state += 1;
|
||||
#endif
|
||||
|
||||
// allocate state for locals and stack
|
||||
mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
|
||||
mp_code_state *code_state;
|
||||
if (state_size > VM_MAX_STATE_ON_STACK) {
|
||||
code_state = m_new_obj_var(mp_code_state, byte, state_size);
|
||||
} else {
|
||||
code_state = alloca(sizeof(mp_code_state) + state_size);
|
||||
}
|
||||
|
||||
code_state->n_state = n_state;
|
||||
code_state->ip = ip;
|
||||
mp_setup_code_state(code_state, self_in, n_args, n_kw, args);
|
||||
|
||||
// execute the byte code with the correct globals context
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
mp_globals_set(self->globals);
|
||||
mp_obj_t result;
|
||||
DEBUG_printf("Calling: args=%p, n_args=%d, extra_args=%p, n_extra_args=%d\n", args, n_args, extra_args, n_extra_args);
|
||||
dump_args(args, n_args);
|
||||
dump_args(extra_args, n_extra_args);
|
||||
mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code(self->bytecode, args, n_args, extra_args, n_extra_args, &result);
|
||||
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL);
|
||||
mp_globals_set(old_globals);
|
||||
|
||||
#if VM_DETECT_STACK_OVERFLOW
|
||||
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
|
||||
if (code_state->sp < code_state->state) {
|
||||
printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
// We can't check the case when an exception is returned in state[n_state - 1]
|
||||
// and there are no arguments, because in this case our detection slot may have
|
||||
// been overwritten by the returned exception (which is allowed).
|
||||
if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) {
|
||||
// Just check to see that we have at least 1 null object left in the state.
|
||||
bool overflow = true;
|
||||
for (mp_uint_t i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) {
|
||||
if (code_state->state[i] == MP_OBJ_NULL) {
|
||||
overflow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overflow) {
|
||||
printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t result;
|
||||
switch (vm_return_kind) {
|
||||
case MP_VM_RETURN_NORMAL:
|
||||
// return value is in *sp
|
||||
result = *code_state->sp;
|
||||
break;
|
||||
|
||||
case MP_VM_RETURN_EXCEPTION:
|
||||
// return value is in state[n_state - 1]
|
||||
result = code_state->state[n_state - 1];
|
||||
break;
|
||||
|
||||
case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
|
||||
default:
|
||||
assert(0);
|
||||
result = mp_const_none;
|
||||
vm_return_kind = MP_VM_RETURN_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
// free the state if it was allocated on the heap
|
||||
if (state_size > VM_MAX_STATE_ON_STACK) {
|
||||
m_del_var(mp_code_state, byte, state_size, code_state);
|
||||
}
|
||||
|
||||
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
|
||||
return result;
|
||||
} else { // MP_VM_RETURN_EXCEPTION
|
||||
@@ -369,22 +458,19 @@ const mp_obj_type_t mp_type_fun_bc = {
|
||||
.print = fun_bc_print,
|
||||
#endif
|
||||
.call = fun_bc_call,
|
||||
.binary_op = fun_binary_op,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, const byte *code) {
|
||||
uint n_def_args = 0;
|
||||
uint n_extra_args = 0;
|
||||
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
|
||||
mp_uint_t n_def_args = 0;
|
||||
mp_uint_t n_extra_args = 0;
|
||||
mp_obj_tuple_t *def_args = def_args_in;
|
||||
if (def_args != MP_OBJ_NULL) {
|
||||
assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
|
||||
n_def_args = def_args->len;
|
||||
n_extra_args = def_args->len;
|
||||
}
|
||||
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
|
||||
n_extra_args += 1;
|
||||
}
|
||||
if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
|
||||
if (def_kw_args != MP_OBJ_NULL) {
|
||||
n_extra_args += 1;
|
||||
}
|
||||
mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
|
||||
@@ -394,38 +480,157 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
|
||||
o->n_pos_args = n_pos_args;
|
||||
o->n_kwonly_args = n_kwonly_args;
|
||||
o->n_def_args = n_def_args;
|
||||
o->has_def_kw_args = def_kw_args != MP_OBJ_NULL;
|
||||
o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
|
||||
o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
|
||||
o->bytecode = code;
|
||||
memset(o->extra_args, 0, n_extra_args * sizeof(mp_obj_t));
|
||||
if (def_args != MP_OBJ_NULL) {
|
||||
memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
|
||||
}
|
||||
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
|
||||
o->extra_args[n_def_args] = MP_OBJ_NULL;
|
||||
}
|
||||
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
|
||||
o->extra_args[n_extra_args - 1] = MP_OBJ_NULL;
|
||||
if (def_kw_args != MP_OBJ_NULL) {
|
||||
o->extra_args[n_def_args] = def_kw_args;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* native functions */
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
typedef struct _mp_obj_fun_native_t {
|
||||
mp_obj_base_t base;
|
||||
mp_uint_t n_args;
|
||||
void *fun_data; // GC must be able to trace this pointer
|
||||
// TODO add mp_map_t *globals
|
||||
} mp_obj_fun_native_t;
|
||||
|
||||
typedef mp_obj_t (*native_fun_0_t)();
|
||||
typedef mp_obj_t (*native_fun_1_t)(mp_obj_t);
|
||||
typedef mp_obj_t (*native_fun_2_t)(mp_obj_t, mp_obj_t);
|
||||
typedef mp_obj_t (*native_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
|
||||
|
||||
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_fun_native_t *self = self_in;
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
return ((native_fun_0_t)fun)();
|
||||
|
||||
case 1:
|
||||
return ((native_fun_1_t)fun)(args[0]);
|
||||
|
||||
case 2:
|
||||
return ((native_fun_2_t)fun)(args[0], args[1]);
|
||||
|
||||
case 3:
|
||||
return ((native_fun_3_t)fun)(args[0], args[1], args[2]);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_fun_native = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_native_call,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data) {
|
||||
assert(0 <= n_args && n_args <= 3);
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->n_args = n_args;
|
||||
o->fun_data = fun_data;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
||||
/******************************************************************************/
|
||||
/* viper functions */
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
typedef struct _mp_obj_fun_viper_t {
|
||||
mp_obj_base_t base;
|
||||
mp_uint_t n_args;
|
||||
void *fun_data; // GC must be able to trace this pointer
|
||||
mp_uint_t type_sig;
|
||||
} mp_obj_fun_viper_t;
|
||||
|
||||
typedef mp_uint_t (*viper_fun_0_t)();
|
||||
typedef mp_uint_t (*viper_fun_1_t)(mp_uint_t);
|
||||
typedef mp_uint_t (*viper_fun_2_t)(mp_uint_t, mp_uint_t);
|
||||
typedef mp_uint_t (*viper_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
|
||||
|
||||
STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_fun_viper_t *self = self_in;
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
|
||||
|
||||
mp_uint_t ret;
|
||||
if (n_args == 0) {
|
||||
ret = ((viper_fun_0_t)fun)();
|
||||
} else if (n_args == 1) {
|
||||
ret = ((viper_fun_1_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2));
|
||||
} else if (n_args == 2) {
|
||||
ret = ((viper_fun_2_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4));
|
||||
} else if (n_args == 3) {
|
||||
ret = ((viper_fun_3_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4), mp_convert_obj_to_native(args[2], self->type_sig >> 6));
|
||||
} else {
|
||||
assert(0);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return mp_convert_native_to_obj(ret, self->type_sig);
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_fun_viper = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_viper_call,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig) {
|
||||
mp_obj_fun_viper_t *o = m_new_obj(mp_obj_fun_viper_t);
|
||||
o->base.type = &mp_type_fun_viper;
|
||||
o->n_args = n_args;
|
||||
o->fun_data = fun_data;
|
||||
o->type_sig = type_sig;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
||||
/******************************************************************************/
|
||||
/* inline assembler functions */
|
||||
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
|
||||
typedef struct _mp_obj_fun_asm_t {
|
||||
mp_obj_base_t base;
|
||||
int n_args;
|
||||
void *fun;
|
||||
mp_uint_t n_args;
|
||||
void *fun_data; // GC must be able to trace this pointer
|
||||
} mp_obj_fun_asm_t;
|
||||
|
||||
typedef machine_uint_t (*inline_asm_fun_0_t)();
|
||||
typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
|
||||
typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
|
||||
typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
|
||||
typedef mp_uint_t (*inline_asm_fun_0_t)();
|
||||
typedef mp_uint_t (*inline_asm_fun_1_t)(mp_uint_t);
|
||||
typedef mp_uint_t (*inline_asm_fun_2_t)(mp_uint_t, mp_uint_t);
|
||||
typedef mp_uint_t (*inline_asm_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
|
||||
|
||||
// convert a Micro Python object to a sensible value for inline asm
|
||||
STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
// TODO for byte_array, pass pointer to the array
|
||||
if (MP_OBJ_IS_SMALL_INT(obj)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(obj);
|
||||
@@ -438,64 +643,61 @@ STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
} else if (MP_OBJ_IS_STR(obj)) {
|
||||
// pointer to the string (it's probably constant though!)
|
||||
uint l;
|
||||
return (machine_uint_t)mp_obj_str_get_data(obj, &l);
|
||||
return (mp_uint_t)mp_obj_str_get_data(obj, &l);
|
||||
} else {
|
||||
mp_obj_type_t *type = mp_obj_get_type(obj);
|
||||
if (0) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (type == &mp_type_float) {
|
||||
// convert float to int (could also pass in float registers)
|
||||
return (machine_int_t)mp_obj_float_get(obj);
|
||||
return (mp_int_t)mp_obj_float_get(obj);
|
||||
#endif
|
||||
} else if (type == &mp_type_tuple) {
|
||||
// pointer to start of tuple (could pass length, but then could use len(x) for that)
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_tuple_get(obj, &len, &items);
|
||||
return (machine_uint_t)items;
|
||||
return (mp_uint_t)items;
|
||||
} else if (type == &mp_type_list) {
|
||||
// pointer to start of list (could pass length, but then could use len(x) for that)
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_list_get(obj, &len, &items);
|
||||
return (machine_uint_t)items;
|
||||
return (mp_uint_t)items;
|
||||
} else {
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) {
|
||||
// supports the buffer protocol, return a pointer to the data
|
||||
return (machine_uint_t)bufinfo.buf;
|
||||
return (mp_uint_t)bufinfo.buf;
|
||||
} else {
|
||||
// just pass along a pointer to the object
|
||||
return (machine_uint_t)obj;
|
||||
return (mp_uint_t)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert a return value from inline asm to a sensible Micro Python object
|
||||
STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
|
||||
STATIC mp_obj_t convert_val_from_inline_asm(mp_uint_t val) {
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_fun_asm_t *self = self_in;
|
||||
|
||||
if (n_args != self->n_args) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args));
|
||||
}
|
||||
if (n_kw != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
|
||||
}
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
machine_uint_t ret;
|
||||
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
|
||||
|
||||
mp_uint_t ret;
|
||||
if (n_args == 0) {
|
||||
ret = ((inline_asm_fun_0_t)self->fun)();
|
||||
ret = ((inline_asm_fun_0_t)fun)();
|
||||
} else if (n_args == 1) {
|
||||
ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
|
||||
ret = ((inline_asm_fun_1_t)fun)(convert_obj_for_inline_asm(args[0]));
|
||||
} else if (n_args == 2) {
|
||||
ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
|
||||
ret = ((inline_asm_fun_2_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
|
||||
} else if (n_args == 3) {
|
||||
ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
|
||||
ret = ((inline_asm_fun_3_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
|
||||
} else {
|
||||
assert(0);
|
||||
ret = 0;
|
||||
@@ -508,13 +710,15 @@ STATIC const mp_obj_type_t mp_type_fun_asm = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_asm_call,
|
||||
.binary_op = fun_binary_op,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
|
||||
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data) {
|
||||
mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
|
||||
o->base.type = &mp_type_fun_asm;
|
||||
o->n_args = n_args;
|
||||
o->fun = fun;
|
||||
o->fun_data = fun_data;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_INLINE_THUMB
|
||||
|
||||
49
py/objfun.h
49
py/objfun.h
@@ -1,13 +1,44 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef struct _mp_obj_fun_bc_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *globals; // the context within which this function was defined
|
||||
machine_uint_t n_pos_args : 16; // number of arguments this function takes
|
||||
machine_uint_t n_kwonly_args : 16; // number of arguments this function takes
|
||||
machine_uint_t n_def_args : 16; // number of default arguments
|
||||
machine_uint_t takes_var_args : 1; // set if this function takes variable args
|
||||
machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
|
||||
const byte *bytecode; // bytecode for the function
|
||||
qstr *args; // argument names (needed to resolve positional args passed as keywords)
|
||||
// values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them)
|
||||
mp_obj_dict_t *globals; // the context within which this function was defined
|
||||
mp_uint_t n_pos_args : 16; // number of arguments this function takes
|
||||
mp_uint_t n_kwonly_args : 16; // number of arguments this function takes
|
||||
mp_uint_t n_def_args : 16; // number of default arguments
|
||||
mp_uint_t has_def_kw_args : 1; // set if this function has default keyword args
|
||||
mp_uint_t takes_var_args : 1; // set if this function takes variable args
|
||||
mp_uint_t takes_kw_args : 1; // set if this function takes keyword args
|
||||
const byte *bytecode; // bytecode for the function
|
||||
qstr *args; // argument names (needed to resolve positional args passed as keywords)
|
||||
// the following extra_args array is allocated space to take (in order):
|
||||
// - values of positional default args (if any)
|
||||
// - a single slot for default kw args dict (if it has them)
|
||||
// - a single slot for var args tuple (if it takes them)
|
||||
// - a single slot for kw args dict (if it takes them)
|
||||
mp_obj_t extra_args[];
|
||||
} mp_obj_fun_bc_t;
|
||||
|
||||
@@ -1,3 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -19,21 +46,37 @@ typedef struct _mp_obj_gen_wrap_t {
|
||||
mp_obj_t *fun;
|
||||
} mp_obj_gen_wrap_t;
|
||||
|
||||
mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args,
|
||||
uint n_args2, const mp_obj_t *args2);
|
||||
typedef struct _mp_obj_gen_instance_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *globals;
|
||||
mp_code_state code_state;
|
||||
} mp_obj_gen_instance_t;
|
||||
|
||||
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_gen_wrap_t *self = self_in;
|
||||
mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun;
|
||||
assert(MP_OBJ_IS_TYPE(self_fun, &mp_type_fun_bc));
|
||||
|
||||
const mp_obj_t *args1, *args2;
|
||||
uint len1, len2;
|
||||
if (!mp_obj_fun_prepare_simple_args(self_fun, n_args, n_kw, args, &len1, &args1, &len2, &args2)) {
|
||||
assert(0);
|
||||
}
|
||||
const byte *bytecode = self_fun->bytecode;
|
||||
// get code info size, and skip the line number table
|
||||
mp_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
|
||||
bytecode += code_info_size;
|
||||
|
||||
return mp_obj_new_gen_instance(self_fun->globals, self_fun->bytecode, len1, args1, len2, args2);
|
||||
// bytecode prelude: get state size and exception stack size
|
||||
mp_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
|
||||
mp_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
|
||||
bytecode += 4;
|
||||
|
||||
// allocate the generator object, with room for local stack and exception stack
|
||||
mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte,
|
||||
n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
|
||||
o->base.type = &mp_type_gen_instance;
|
||||
|
||||
o->globals = self_fun->globals;
|
||||
o->code_state.n_state = n_state;
|
||||
o->code_state.ip = bytecode;
|
||||
mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args);
|
||||
return o;
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_gen_wrap = {
|
||||
@@ -52,49 +95,28 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) {
|
||||
/******************************************************************************/
|
||||
/* generator instance */
|
||||
|
||||
typedef struct _mp_obj_gen_instance_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *globals;
|
||||
const byte *code_info;
|
||||
const byte *ip;
|
||||
mp_obj_t *sp;
|
||||
// bit 0 is saved currently_in_except_block value
|
||||
mp_exc_stack_t *exc_sp;
|
||||
uint n_state;
|
||||
// Variable-length
|
||||
mp_obj_t state[0];
|
||||
// Variable-length, never accessed by name, only as (void*)(state + n_state)
|
||||
mp_exc_stack_t exc_state[0];
|
||||
} mp_obj_gen_instance_t;
|
||||
|
||||
void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_gen_instance_t *self = self_in;
|
||||
print(env, "<generator object '%s' at %p>", mp_obj_code_get_name(self->code_info), self_in);
|
||||
}
|
||||
|
||||
mp_obj_t gen_instance_getiter(mp_obj_t self_in) {
|
||||
return self_in;
|
||||
print(env, "<generator object '%s' at %p>", mp_obj_code_get_name(self->code_state.code_info), self_in);
|
||||
}
|
||||
|
||||
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance));
|
||||
mp_obj_gen_instance_t *self = self_in;
|
||||
if (self->ip == 0) {
|
||||
if (self->code_state.ip == 0) {
|
||||
*ret_val = MP_OBJ_STOP_ITERATION;
|
||||
return MP_VM_RETURN_NORMAL;
|
||||
}
|
||||
if (self->sp == self->state - 1) {
|
||||
if (self->code_state.sp == self->code_state.state - 1) {
|
||||
if (send_value != mp_const_none) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator"));
|
||||
}
|
||||
} else {
|
||||
*self->sp = send_value;
|
||||
*self->code_state.sp = send_value;
|
||||
}
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
mp_globals_set(self->globals);
|
||||
mp_vm_return_kind_t ret_kind = mp_execute_byte_code_2(self->code_info, &self->ip,
|
||||
&self->state[self->n_state - 1], &self->sp, (mp_exc_stack_t*)(self->state + self->n_state),
|
||||
&self->exc_sp, throw_value);
|
||||
mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
|
||||
mp_globals_set(old_globals);
|
||||
|
||||
switch (ret_kind) {
|
||||
@@ -104,17 +126,17 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
|
||||
// again and again, leading to side effects.
|
||||
// TODO: check how return with value behaves under such conditions
|
||||
// in CPython.
|
||||
self->ip = 0;
|
||||
*ret_val = *self->sp;
|
||||
self->code_state.ip = 0;
|
||||
*ret_val = *self->code_state.sp;
|
||||
break;
|
||||
|
||||
case MP_VM_RETURN_YIELD:
|
||||
*ret_val = *self->sp;
|
||||
*ret_val = *self->code_state.sp;
|
||||
break;
|
||||
|
||||
case MP_VM_RETURN_EXCEPTION:
|
||||
self->ip = 0;
|
||||
*ret_val = self->state[self->n_state - 1];
|
||||
self->code_state.ip = 0;
|
||||
*ret_val = self->code_state.state[self->code_state.n_state - 1];
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -224,53 +246,7 @@ const mp_obj_type_t mp_type_gen_instance = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_generator,
|
||||
.print = gen_instance_print,
|
||||
.getiter = gen_instance_getiter,
|
||||
.getiter = mp_identity,
|
||||
.iternext = gen_instance_iternext,
|
||||
.locals_dict = (mp_obj_t)&gen_instance_locals_dict,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args,
|
||||
uint n_args2, const mp_obj_t *args2) {
|
||||
const byte *code_info = bytecode;
|
||||
// get code info size, and skip the line number table
|
||||
machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
|
||||
bytecode += code_info_size;
|
||||
|
||||
// bytecode prelude: get state size and exception stack size
|
||||
machine_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
|
||||
machine_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
|
||||
bytecode += 4;
|
||||
|
||||
// allocate the generator object, with room for local stack and exception stack
|
||||
mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
|
||||
o->base.type = &mp_type_gen_instance;
|
||||
o->globals = globals;
|
||||
o->code_info = code_info;
|
||||
o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state
|
||||
o->exc_sp = (mp_exc_stack_t*)(o->state + n_state) - 1;
|
||||
o->n_state = n_state;
|
||||
|
||||
// copy args to end of state array, in reverse (that's how mp_execute_byte_code_2 needs it)
|
||||
for (uint i = 0; i < n_args; i++) {
|
||||
o->state[n_state - 1 - i] = args[i];
|
||||
}
|
||||
for (uint i = 0; i < n_args2; i++) {
|
||||
o->state[n_state - 1 - n_args - i] = args2[i];
|
||||
}
|
||||
|
||||
// set rest of state to MP_OBJ_NULL
|
||||
for (uint i = 0; i < n_state - n_args - n_args2; i++) {
|
||||
o->state[i] = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
for (uint n_local = *bytecode++; n_local > 0; n_local--) {
|
||||
uint local_num = *bytecode++;
|
||||
o->state[n_state - 1 - local_num] = mp_obj_new_cell(o->state[n_state - 1 - local_num]);
|
||||
}
|
||||
|
||||
// set ip to start of actual byte code
|
||||
o->ip = bytecode;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -1 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_val, mp_obj_t throw_val, mp_obj_t *ret_val);
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
|
||||
93
py/objint.c
93
py/objint.c
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
@@ -9,55 +35,58 @@
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "parsenum.h"
|
||||
#include "smallint.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "objstr.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
// This dispatcher function is expected to be independent of the implementation of long int
|
||||
STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
// TODO check n_kw == 0
|
||||
mp_arg_check_num(n_args, n_kw, 0, 2, false);
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
|
||||
case 1:
|
||||
if (MP_OBJ_IS_STR(args[0])) {
|
||||
if (MP_OBJ_IS_INT(args[0])) {
|
||||
// already an int (small or long), just return it
|
||||
return args[0];
|
||||
} else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) {
|
||||
// a string, parse it
|
||||
uint l;
|
||||
const char *s = mp_obj_str_get_data(args[0], &l);
|
||||
return mp_parse_num_integer(s, l, 0);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)(MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
|
||||
return MP_OBJ_NEW_SMALL_INT((MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
|
||||
#endif
|
||||
} else {
|
||||
// try to convert to small int (eg from bool)
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
default: {
|
||||
// should be a string, parse it
|
||||
// TODO proper error checking of argument types
|
||||
uint l;
|
||||
const char *s = mp_obj_str_get_data(args[0], &l);
|
||||
return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]));
|
||||
}
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "int takes at most 2 arguments, %d given", n_args));
|
||||
}
|
||||
}
|
||||
|
||||
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
// The size of this buffer is rather arbitrary. If it's not large
|
||||
// enough, a dynamic one will be allocated.
|
||||
char stack_buf[sizeof(machine_int_t) * 4];
|
||||
char stack_buf[sizeof(mp_int_t) * 4];
|
||||
char *buf = stack_buf;
|
||||
int buf_size = sizeof(stack_buf);
|
||||
int fmt_size;
|
||||
@@ -73,7 +102,7 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||
typedef mp_longint_impl_t fmt_int_t;
|
||||
#else
|
||||
typedef mp_small_int_t fmt_int_t;
|
||||
typedef mp_int_t fmt_int_t;
|
||||
#endif
|
||||
|
||||
STATIC const uint log_base2_floor[] = {
|
||||
@@ -99,14 +128,14 @@ STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma)
|
||||
return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
|
||||
}
|
||||
|
||||
// This routine expects you to pass in a buffer and size (in *buf and buf_size).
|
||||
// This routine expects you to pass in a buffer and size (in *buf and *buf_size).
|
||||
// If, for some reason, this buffer is too small, then it will allocate a
|
||||
// buffer and return the allocated buffer and size in *buf and *buf_size. It
|
||||
// is the callers responsibility to free this allocated buffer.
|
||||
//
|
||||
// The resulting formatted string will be returned from this function and the
|
||||
// formatted size will be in *fmt_size.
|
||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
int base, const char *prefix, char base_char, char comma) {
|
||||
fmt_int_t num;
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
@@ -116,8 +145,8 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
|
||||
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
|
||||
// Not a small int.
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||
mp_obj_int_t *self = self_in;
|
||||
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
|
||||
const mp_obj_int_t *self = self_in;
|
||||
// Get the value to format; mp_obj_get_int truncates to mp_int_t.
|
||||
num = self->val;
|
||||
#else
|
||||
// Delegate to the implementation for the long int.
|
||||
@@ -126,7 +155,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
|
||||
#endif
|
||||
} else {
|
||||
// Not an int.
|
||||
buf[0] = '\0';
|
||||
**buf = '\0';
|
||||
*fmt_size = 0;
|
||||
return *buf;
|
||||
}
|
||||
@@ -187,13 +216,17 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
|
||||
|
||||
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||
return mp_obj_get_int(self_in) >= 0;
|
||||
}
|
||||
|
||||
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
|
||||
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
// This is called for operations on SMALL_INT that are not handled by mp_binary_op
|
||||
@@ -202,7 +235,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
}
|
||||
|
||||
// This is called only with strings whose value doesn't fit in SMALL_INT
|
||||
mp_obj_t mp_obj_new_int_from_long_str(const char *s) {
|
||||
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -213,7 +246,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
|
||||
// SMALL_INT accepts only signed numbers, of one bit less size
|
||||
// then word size, which totals 2 bits less for unsigned numbers.
|
||||
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
|
||||
@@ -223,23 +256,23 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value) {
|
||||
if (MP_OBJ_FITS_SMALL_INT(value)) {
|
||||
mp_obj_t mp_obj_new_int(mp_int_t value) {
|
||||
if (MP_SMALL_INT_FITS(value)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
@@ -257,12 +290,12 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_
|
||||
// true acts as 0
|
||||
return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
|
||||
} else if (op == MP_BINARY_OP_MULTIPLY) {
|
||||
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
|
||||
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
|
||||
// multiply is commutative for these types, so delegate to them
|
||||
return mp_binary_op(op, rhs_in, lhs_in);
|
||||
}
|
||||
}
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
// this is a classmethod
|
||||
@@ -276,8 +309,8 @@ STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) {
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
// convert the bytes to an integer
|
||||
machine_uint_t value = 0;
|
||||
for (const byte* buf = bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
|
||||
mp_uint_t value = 0;
|
||||
for (const byte* buf = (const byte*)bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
|
||||
value = (value << 8) | *buf;
|
||||
}
|
||||
|
||||
@@ -288,7 +321,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 3, int_fro
|
||||
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, (const mp_obj_t)&int_from_bytes_fun_obj);
|
||||
|
||||
STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
|
||||
machine_int_t val = mp_obj_int_get_checked(args[0]);
|
||||
mp_int_t val = mp_obj_int_get_checked(args[0]);
|
||||
|
||||
uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
||||
byte *data;
|
||||
@@ -298,7 +331,7 @@ STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
|
||||
// TODO: Support signed param
|
||||
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
|
||||
memset(data, 0, len);
|
||||
memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t));
|
||||
memcpy(data, &val, len < sizeof(mp_int_t) ? len : sizeof(mp_int_t));
|
||||
return mp_obj_str_builder_end(o);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user