mirror of
https://github.com/micropython/micropython.git
synced 2025-12-26 14:50:12 +01:00
Compare commits
386 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dce8876dbe | ||
|
|
ac736f15c9 | ||
|
|
122c9db3db | ||
|
|
a1760a56ff | ||
|
|
b82f34edde | ||
|
|
2cf381081a | ||
|
|
564e46452d | ||
|
|
58c9586c34 | ||
|
|
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 | ||
|
|
9e040b7cd8 | ||
|
|
9e76b1181b |
@@ -20,4 +20,4 @@ script:
|
||||
- (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)
|
||||
|
||||
@@ -29,15 +29,13 @@ 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.
|
||||
|
||||
@@ -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 = \
|
||||
|
||||
@@ -2,26 +2,33 @@
|
||||
|
||||
// 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_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
|
||||
|
||||
@@ -30,13 +37,15 @@
|
||||
#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 \
|
||||
#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>
|
||||
|
||||
@@ -2,9 +2,9 @@ import pyb
|
||||
|
||||
def led_angle(seconds_to_run_for):
|
||||
# make LED objects
|
||||
l1 = pyb.Led(1)
|
||||
l2 = pyb.Led(2)
|
||||
accel = pyb.Accel()
|
||||
l1 = pyb.LED(1)
|
||||
l2 = pyb.LED(2)
|
||||
accel = pyb.Accel()
|
||||
|
||||
for i in range(20 * seconds_to_run_for):
|
||||
# get x-axis
|
||||
|
||||
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()
|
||||
633
extmod/moductypes.c
Normal file
633
extmod/moductypes.c
Normal file
@@ -0,0 +1,633 @@
|
||||
#include <stdio.h>
|
||||
/*
|
||||
* 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((mp_int_t)((uint8_t*)p)[index]);
|
||||
case INT8:
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_int_t)((int8_t*)p)[index]);
|
||||
case UINT16:
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_int_t)((uint16_t*)p)[index]);
|
||||
case INT16:
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_int_t)((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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} 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
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmthumb.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
@@ -133,7 +133,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 (void *)(((mp_uint_t)as->code_base) | 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -378,7 +378,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
|
||||
|
||||
@@ -499,7 +499,7 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
|
||||
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_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr);
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
} else if (1) {
|
||||
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));
|
||||
|
||||
@@ -185,7 +185,7 @@ 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
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#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
|
||||
|
||||
25
py/bc.h
25
py/bc.h
@@ -36,12 +36,25 @@ typedef struct _mp_exc_stack {
|
||||
byte opcode;
|
||||
} mp_exc_stack_t;
|
||||
|
||||
mp_vm_return_kind_t mp_execute_bytecode(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_bytecode2(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_bytecode_print(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, uint n_args, uint 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))
|
||||
|
||||
101
py/binary.c
101
py/binary.c
@@ -26,10 +26,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.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"
|
||||
@@ -75,7 +76,7 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
case 'q': case 'Q':
|
||||
// TODO: This is for x86
|
||||
align = sizeof(int); size = sizeof(long long); break;
|
||||
case 'P': case 'O':
|
||||
case 'P': case 'O': case 'S':
|
||||
align = size = sizeof(void*); break;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +88,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];
|
||||
@@ -114,7 +115,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':
|
||||
@@ -124,6 +125,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;
|
||||
@@ -132,35 +155,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 {
|
||||
@@ -168,6 +177,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;
|
||||
@@ -175,18 +201,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':
|
||||
@@ -196,28 +223,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;
|
||||
@@ -230,7 +241,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;
|
||||
@@ -260,7 +271,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;
|
||||
|
||||
@@ -31,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);
|
||||
|
||||
81
py/builtin.c
81
py/builtin.c
@@ -37,7 +37,7 @@
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
@@ -99,12 +99,12 @@ 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) {
|
||||
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
|
||||
@@ -113,10 +113,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);
|
||||
@@ -154,7 +156,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);
|
||||
@@ -170,13 +172,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_int_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);
|
||||
@@ -221,8 +250,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);
|
||||
@@ -342,13 +371,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);
|
||||
@@ -391,7 +439,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;
|
||||
}
|
||||
@@ -430,7 +478,7 @@ 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);
|
||||
return mp_obj_new_int((mp_int_t)o_in);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_builtin_id);
|
||||
@@ -452,12 +500,17 @@ 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);
|
||||
@@ -466,7 +519,7 @@ 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.3/library/functions.html?highlight=hasattr#hasattr
|
||||
// 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.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
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_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
|
||||
@@ -79,3 +80,6 @@ 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;
|
||||
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -28,7 +29,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
@@ -54,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) {
|
||||
@@ -68,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
|
||||
|
||||
@@ -102,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));
|
||||
|
||||
@@ -162,16 +162,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");
|
||||
@@ -277,7 +267,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;
|
||||
@@ -315,9 +305,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));
|
||||
// https://docs.python.org/3.3/reference/import.html
|
||||
// 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((byte*)vstr_str(&path), vstr_len(&path), false));
|
||||
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) {
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -43,28 +43,32 @@ 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_ENABLE_FROZENSET
|
||||
#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 },
|
||||
#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 },
|
||||
@@ -140,7 +144,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 = {
|
||||
@@ -148,8 +152,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,
|
||||
},
|
||||
};
|
||||
@@ -158,32 +162,42 @@ 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_ENABLE_MOD_GC && MICROPY_ENABLE_GC
|
||||
#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
|
||||
|
||||
// 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 = {
|
||||
@@ -191,8 +205,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,
|
||||
},
|
||||
};
|
||||
|
||||
171
py/compile.c
171
py/compile.c
@@ -31,8 +31,8 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -56,6 +56,7 @@ typedef enum {
|
||||
#include "grammar.h"
|
||||
#undef DEF_RULE
|
||||
PN_maximum_number_of,
|
||||
PN_string, // special node for non-interned string
|
||||
} pn_kind_t;
|
||||
|
||||
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
|
||||
@@ -72,8 +73,8 @@ typedef struct _compiler_t {
|
||||
|
||||
uint next_label;
|
||||
|
||||
uint break_label;
|
||||
uint continue_label;
|
||||
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||
uint16_t continue_label;
|
||||
int break_continue_except_level;
|
||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||
|
||||
@@ -94,7 +95,7 @@ typedef struct _compiler_t {
|
||||
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
|
||||
// TODO store the error message to a variable in compiler_t instead of printing it
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (machine_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
} else {
|
||||
printf(" File \"%s\"\n", qstr_str(comp->source_file));
|
||||
}
|
||||
@@ -103,15 +104,18 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
// Extra constants as defined by a port
|
||||
MICROPY_EXTRA_CONSTANTS
|
||||
MICROPY_PORT_CONSTANTS
|
||||
};
|
||||
|
||||
STATIC const mp_map_t mp_constants_map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = ARRAY_SIZE(mp_constants_table),
|
||||
.used = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.table = (mp_map_elem_t*)mp_constants_table,
|
||||
};
|
||||
|
||||
@@ -119,7 +123,7 @@ STATIC const mp_map_t mp_constants_map = {
|
||||
STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_map_t *consts) {
|
||||
if (0) {
|
||||
// dummy
|
||||
#if MICROPY_ENABLE_CONST
|
||||
#if MICROPY_COMP_CONST
|
||||
} else if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
// lookup identifier in table of dynamic constants
|
||||
qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
@@ -133,7 +137,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
// fold some parse nodes before folding their arguments
|
||||
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
|
||||
#if MICROPY_ENABLE_CONST
|
||||
#if MICROPY_COMP_CONST
|
||||
case PN_expr_stmt:
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
||||
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
|
||||
@@ -157,7 +161,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "constant must be an integer");
|
||||
break;
|
||||
}
|
||||
machine_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
|
||||
mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
|
||||
|
||||
// store the value in the table of dynamic constants
|
||||
mp_map_elem_t *elem = mp_map_lookup(consts, MP_OBJ_NEW_QSTR(id_qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
@@ -177,6 +181,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PN_string:
|
||||
return pn;
|
||||
}
|
||||
|
||||
// fold arguments
|
||||
@@ -197,8 +203,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
case PN_expr:
|
||||
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
// int | int
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
|
||||
}
|
||||
break;
|
||||
@@ -206,16 +212,16 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
case PN_and_expr:
|
||||
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
// int & int
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
|
||||
}
|
||||
break;
|
||||
|
||||
case PN_shift_expr:
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
|
||||
// int << int
|
||||
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
|
||||
@@ -232,10 +238,10 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
break;
|
||||
|
||||
case PN_arith_expr:
|
||||
// overflow checking here relies on SMALL_INT being strictly smaller than machine_int_t
|
||||
// overflow checking here relies on SMALL_INT being strictly smaller than mp_int_t
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
|
||||
// int + int
|
||||
arg0 += arg1;
|
||||
@@ -246,7 +252,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
// shouldn't happen
|
||||
assert(0);
|
||||
}
|
||||
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
|
||||
if (MP_SMALL_INT_FITS(arg0)) {
|
||||
//printf("%ld + %ld\n", arg0, arg1);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
|
||||
}
|
||||
@@ -255,13 +261,13 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
case PN_term:
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
|
||||
// int * int
|
||||
if (!mp_small_int_mul_overflow(arg0, arg1)) {
|
||||
arg0 *= arg1;
|
||||
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
|
||||
if (MP_SMALL_INT_FITS(arg0)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
|
||||
}
|
||||
}
|
||||
@@ -285,7 +291,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
case PN_factor_2:
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
|
||||
// +int
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
|
||||
@@ -333,8 +339,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(elem->value, q_attr, dest);
|
||||
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
|
||||
machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
if (MP_PARSE_FITS_SMALL_INT(val)) {
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
if (MP_SMALL_INT_FITS(val)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
|
||||
}
|
||||
}
|
||||
@@ -426,6 +432,9 @@ void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
return true;
|
||||
}
|
||||
if (!MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
return false;
|
||||
}
|
||||
@@ -435,9 +444,7 @@ STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
|
||||
uint len;
|
||||
const byte *str = qstr_data(qstr, &len);
|
||||
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
@@ -476,6 +483,12 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
|
||||
}
|
||||
|
||||
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(MP_PARSE_NODE_IS_LEAF(pn));
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
|
||||
@@ -487,8 +500,13 @@ STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vst
|
||||
case MP_PARSE_NODE_ID: assert(0);
|
||||
case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_STRING: cpython_c_print_quoted_str(vstr, arg, false); break;
|
||||
case MP_PARSE_NODE_BYTES: cpython_c_print_quoted_str(vstr, arg, true); break;
|
||||
case MP_PARSE_NODE_STRING:
|
||||
case MP_PARSE_NODE_BYTES: {
|
||||
uint len;
|
||||
const byte *str = qstr_data(arg, &len);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
|
||||
break;
|
||||
}
|
||||
case MP_PARSE_NODE_TOKEN:
|
||||
switch (arg) {
|
||||
case MP_TOKEN_KW_FALSE: vstr_printf(vstr, "False"); break;
|
||||
@@ -1020,7 +1038,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
|
||||
if (comp->have_star) {
|
||||
comp->num_dict_params += 1;
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
|
||||
compile_node(comp, pn_equal);
|
||||
#else
|
||||
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
||||
if (comp->num_dict_params == 1) {
|
||||
// in Micro Python we put the default positional parameters into a tuple using the bytecode
|
||||
@@ -1033,11 +1054,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
// first default dict param, so make the map
|
||||
EMIT_ARG(build_map, 0);
|
||||
}
|
||||
#endif
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
|
||||
|
||||
// compile value then key, then store it to the dict
|
||||
compile_node(comp, pn_equal);
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
|
||||
EMIT(store_map);
|
||||
#endif
|
||||
} else {
|
||||
@@ -1147,7 +1167,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_
|
||||
|
||||
qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
|
||||
if (attr == MP_QSTR_bytecode) {
|
||||
*emit_options = MP_EMIT_OPT_BYTE_CODE;
|
||||
*emit_options = MP_EMIT_OPT_BYTECODE;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
} else if (attr == MP_QSTR_native) {
|
||||
*emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
|
||||
@@ -1730,6 +1750,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// And, if the loop never runs, the loop variable should never be assigned
|
||||
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
// note that we don't need to pop anything when breaking from an optimise for loop
|
||||
|
||||
uint top_label = comp_next_label(comp);
|
||||
uint entry_label = comp_next_label(comp);
|
||||
@@ -1828,6 +1849,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
#endif
|
||||
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||
|
||||
uint pop_label = comp_next_label(comp);
|
||||
uint end_label = comp_next_label(comp);
|
||||
@@ -1875,7 +1897,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
|
||||
EMIT_ARG(jump, success_label); // jump over exception handler
|
||||
|
||||
EMIT_ARG(label_assign, l1); // start of exception handler
|
||||
EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
|
||||
EMIT(start_except_handler);
|
||||
|
||||
uint l2 = comp_next_label(comp);
|
||||
|
||||
@@ -1947,7 +1969,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
|
||||
|
||||
compile_decrease_except_level(comp);
|
||||
EMIT(end_finally);
|
||||
EMIT_ARG(adjust_stack_size, -5); // stack adjust
|
||||
EMIT(end_except_handler);
|
||||
|
||||
EMIT_ARG(label_assign, success_label);
|
||||
compile_node(comp, pn_else); // else block, can be null
|
||||
@@ -2058,7 +2080,8 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
} else {
|
||||
// for non-REPL, evaluate then discard the expression
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0])) {
|
||||
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0]))
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
|
||||
// do nothing with a lonely constant
|
||||
} else {
|
||||
compile_node(comp, pns->nodes[0]); // just an expression
|
||||
@@ -2498,26 +2521,40 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
int n_bytes = 0;
|
||||
int string_kind = MP_PARSE_NODE_NULL;
|
||||
for (int i = 0; i < n; i++) {
|
||||
assert(MP_PARSE_NODE_IS_LEAF(pns->nodes[i]));
|
||||
int pn_kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[i]);
|
||||
assert(pn_kind == MP_PARSE_NODE_STRING || pn_kind == MP_PARSE_NODE_BYTES);
|
||||
int pn_kind;
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
pn_kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[i]);
|
||||
assert(pn_kind == MP_PARSE_NODE_STRING || pn_kind == MP_PARSE_NODE_BYTES);
|
||||
n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i]));
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string);
|
||||
pn_kind = MP_PARSE_NODE_STRING;
|
||||
n_bytes += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
if (i == 0) {
|
||||
string_kind = pn_kind;
|
||||
} else if (pn_kind != string_kind) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "cannot mix bytes and nonbytes literals");
|
||||
return;
|
||||
}
|
||||
n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
|
||||
}
|
||||
|
||||
// concatenate string/bytes
|
||||
byte *q_ptr;
|
||||
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint s_len;
|
||||
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
|
||||
memcpy(s_dest, s, s_len);
|
||||
s_dest += s_len;
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
uint s_len;
|
||||
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
|
||||
memcpy(s_dest, s, s_len);
|
||||
s_dest += s_len;
|
||||
} else {
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
memcpy(s_dest, (const char*)pns_string->nodes[0], (mp_uint_t)pns_string->nodes[1]);
|
||||
s_dest += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
}
|
||||
qstr q = qstr_build_end(q_ptr);
|
||||
|
||||
@@ -2824,10 +2861,10 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
// pass
|
||||
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
EMIT_ARG(load_const_small_int, arg);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break;
|
||||
case MP_PARSE_NODE_INTEGER: EMIT_ARG(load_const_int, arg); break;
|
||||
@@ -2848,15 +2885,19 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
} else {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
EMIT_ARG(set_line_number, pns->source_line);
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
mp_parse_node_print(pn, 0);
|
||||
#endif
|
||||
compile_syntax_error(comp, pn, "internal compiler error");
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_string) {
|
||||
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]), false);
|
||||
} else {
|
||||
f(comp, pns);
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
mp_parse_node_print(pn, 0);
|
||||
#endif
|
||||
compile_syntax_error(comp, pn, "internal compiler error");
|
||||
} else {
|
||||
f(comp, pns);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3033,13 +3074,13 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {
|
||||
// check the first statement for a doc string
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) {
|
||||
mp_parse_node_struct_t* pns = (mp_parse_node_struct_t*)pn;
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0])) {
|
||||
int kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]);
|
||||
if (kind == MP_PARSE_NODE_STRING) {
|
||||
compile_node(comp, pns->nodes[0]); // a doc string
|
||||
// store doc string
|
||||
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0])
|
||||
&& MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING)
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
|
||||
// compile the doc string
|
||||
compile_node(comp, pns->nodes[0]);
|
||||
// store the doc string
|
||||
EMIT_ARG(store_id, MP_QSTR___doc__);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -3299,7 +3340,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
return;
|
||||
}
|
||||
if (pass > MP_PASS_SCOPE) {
|
||||
machine_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
|
||||
compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments");
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
// 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,
|
||||
|
||||
@@ -44,6 +44,8 @@ typedef enum {
|
||||
#define MP_EMIT_STAR_FLAG_SINGLE (0x01)
|
||||
#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)
|
||||
|
||||
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
|
||||
|
||||
typedef struct _emit_t emit_t;
|
||||
|
||||
typedef struct _emit_method_table_t {
|
||||
@@ -63,7 +65,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);
|
||||
@@ -132,6 +134,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);
|
||||
|
||||
48
py/emitbc.c
48
py/emitbc.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -50,7 +50,6 @@
|
||||
struct _emit_t {
|
||||
pass_kind_t pass : 8;
|
||||
uint last_emit_was_return_value : 8;
|
||||
byte dummy_data[DUMMY_DATA_SIZE];
|
||||
|
||||
int stack_size;
|
||||
|
||||
@@ -67,6 +66,8 @@ struct _emit_t {
|
||||
uint bytecode_offset;
|
||||
uint bytecode_size;
|
||||
byte *code_base; // stores both byte code and code info
|
||||
// Accessed as uint, so must be aligned as such
|
||||
byte dummy_data[DUMMY_DATA_SIZE];
|
||||
};
|
||||
|
||||
STATIC void emit_bc_rot_two(emit_t *emit);
|
||||
@@ -99,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) {
|
||||
@@ -139,7 +140,7 @@ STATIC byte* emit_get_cur_to_write_bytecode(emit_t* emit, int num_bytes_to_write
|
||||
}
|
||||
|
||||
STATIC void emit_align_bytecode_to_machine_word(emit_t* emit) {
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
|
||||
}
|
||||
|
||||
STATIC void emit_write_bytecode_byte(emit_t* emit, byte b1) {
|
||||
@@ -171,7 +172,7 @@ STATIC void emit_write_bytecode_uint(emit_t* emit, uint num) {
|
||||
}
|
||||
|
||||
// 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, machine_int_t num) {
|
||||
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
|
||||
@@ -206,8 +207,10 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, uint num) {
|
||||
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);
|
||||
machine_uint_t *c = (machine_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(machine_uint_t));
|
||||
*c = (machine_uint_t)ptr;
|
||||
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
|
||||
@@ -269,7 +272,7 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
// 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;
|
||||
@@ -352,6 +355,10 @@ 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->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->bytecode_offset - emit->last_source_line_offset;
|
||||
uint lines_to_skip = source_line - emit->last_source_line;
|
||||
@@ -424,7 +431,7 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
}
|
||||
}
|
||||
|
||||
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_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
}
|
||||
@@ -617,11 +624,15 @@ STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint 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_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label);
|
||||
emit_write_bytecode_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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -841,6 +852,14 @@ STATIC void emit_bc_yield_from(emit_t *emit) {
|
||||
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_start_pass,
|
||||
@@ -926,6 +945,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
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
|
||||
15
py/emitcpy.c
15
py/emitcpy.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -173,7 +173,7 @@ 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 == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST " INT_FMT "\n", arg);
|
||||
@@ -792,6 +792,14 @@ STATIC void emit_cpy_yield_from(emit_t *emit) {
|
||||
}
|
||||
}
|
||||
|
||||
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 == MP_PASS_EMIT) {
|
||||
@@ -899,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,
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -49,24 +49,6 @@
|
||||
#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;
|
||||
@@ -89,17 +71,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
|
||||
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
|
||||
if (mp_verbose_flag > 0) {
|
||||
mp_bytecode_print(code, len);
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" %02x", code[i]);
|
||||
}
|
||||
printf("\n");
|
||||
mp_bytecode_print(rc, code, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -113,7 +95,7 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign native: kind=%d fun=%p len=%u n_args=%d\n", kind, fun, len, n_args);
|
||||
byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
|
||||
byte *fun_data = (byte*)(((mp_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");
|
||||
@@ -123,10 +105,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
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, len, 1, fp_write_code);
|
||||
fclose(fp_write_code);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -138,14 +119,14 @@ 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_BYTECODE:
|
||||
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);
|
||||
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_PY:
|
||||
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
|
||||
|
||||
@@ -52,9 +52,6 @@ typedef struct _mp_code_t {
|
||||
};
|
||||
} 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_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -167,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) {
|
||||
@@ -286,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;
|
||||
}
|
||||
|
||||
167
py/emitnative.c
167
py/emitnative.c
@@ -48,8 +48,9 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -139,7 +140,7 @@ typedef struct _stack_info_t {
|
||||
stack_info_kind_t kind;
|
||||
union {
|
||||
int u_reg;
|
||||
machine_int_t u_imm;
|
||||
mp_int_t u_imm;
|
||||
};
|
||||
} stack_info_t;
|
||||
|
||||
@@ -284,7 +285,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
||||
}
|
||||
}
|
||||
|
||||
asm_thumb_mov_reg_i32(emit->as, REG_R7, (machine_uint_t)mp_fun_table);
|
||||
asm_thumb_mov_reg_i32(emit->as, REG_R7, (mp_uint_t)mp_fun_table);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -471,7 +472,7 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {
|
||||
adjust_stack(emit, 1);
|
||||
}
|
||||
|
||||
STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, machine_int_t imm) {
|
||||
STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {
|
||||
stack_info_t *si = &emit->stack_info[emit->stack_size];
|
||||
si->vtype = vtype;
|
||||
si->kind = STACK_IMM;
|
||||
@@ -515,9 +516,9 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, int reg_dest, in
|
||||
case VTYPE_BOOL:
|
||||
si->vtype = VTYPE_PYOBJ;
|
||||
if (si->u_imm == 0) {
|
||||
ASM_MOV_IMM_TO_LOCAL_USING((machine_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
ASM_MOV_IMM_TO_LOCAL_USING((mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
} else {
|
||||
ASM_MOV_IMM_TO_LOCAL_USING((machine_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
ASM_MOV_IMM_TO_LOCAL_USING((mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
}
|
||||
break;
|
||||
case VTYPE_INT:
|
||||
@@ -556,7 +557,7 @@ STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind, void *fun) {
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val, int arg_reg) {
|
||||
STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, mp_int_t arg_val, int arg_reg) {
|
||||
need_reg_all(emit);
|
||||
ASM_MOV_IMM_TO_REG(arg_val, arg_reg);
|
||||
#if N_X64
|
||||
@@ -566,8 +567,8 @@ STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, void *f
|
||||
#endif
|
||||
}
|
||||
|
||||
// the first arg is stored in the code aligned on a machine_uint_t boundary
|
||||
STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val, int arg_reg) {
|
||||
// the first arg is stored in the code aligned on a mp_uint_t boundary
|
||||
STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, mp_int_t arg_val, int arg_reg) {
|
||||
need_reg_all(emit);
|
||||
ASM_MOV_ALIGNED_IMM_TO_REG(arg_val, arg_reg);
|
||||
#if N_X64
|
||||
@@ -577,7 +578,7 @@ STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind,
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val1, int arg_reg1, machine_int_t arg_val2, int arg_reg2) {
|
||||
STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) {
|
||||
need_reg_all(emit);
|
||||
ASM_MOV_IMM_TO_REG(arg_val1, arg_reg1);
|
||||
ASM_MOV_IMM_TO_REG(arg_val2, arg_reg2);
|
||||
@@ -588,8 +589,8 @@ STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, void
|
||||
#endif
|
||||
}
|
||||
|
||||
// the first arg is stored in the code aligned on a machine_uint_t boundary
|
||||
STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val1, int arg_reg1, machine_int_t arg_val2, int arg_reg2, machine_int_t arg_val3, int arg_reg3) {
|
||||
// the first arg is stored in the code aligned on a mp_uint_t boundary
|
||||
STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2, mp_int_t arg_val3, int arg_reg3) {
|
||||
need_reg_all(emit);
|
||||
ASM_MOV_ALIGNED_IMM_TO_REG(arg_val1, arg_reg1);
|
||||
ASM_MOV_IMM_TO_REG(arg_val2, arg_reg2);
|
||||
@@ -670,7 +671,7 @@ STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
DEBUG_printf("load_const_tok %d\n", tok);
|
||||
emit_native_pre(emit);
|
||||
int vtype;
|
||||
machine_uint_t val;
|
||||
mp_uint_t val;
|
||||
if (emit->do_viper_types) {
|
||||
switch (tok) {
|
||||
case MP_TOKEN_KW_NONE: vtype = VTYPE_PTR_NONE; val = 0; break;
|
||||
@@ -681,16 +682,16 @@ STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
} else {
|
||||
vtype = VTYPE_PYOBJ;
|
||||
switch (tok) {
|
||||
case MP_TOKEN_KW_NONE: val = (machine_uint_t)mp_const_none; break;
|
||||
case MP_TOKEN_KW_FALSE: val = (machine_uint_t)mp_const_false; break;
|
||||
case MP_TOKEN_KW_TRUE: val = (machine_uint_t)mp_const_true; break;
|
||||
case MP_TOKEN_KW_NONE: val = (mp_uint_t)mp_const_none; break;
|
||||
case MP_TOKEN_KW_FALSE: val = (mp_uint_t)mp_const_false; break;
|
||||
case MP_TOKEN_KW_TRUE: val = (mp_uint_t)mp_const_true; break;
|
||||
default: assert(0); vtype = 0; val = 0; // shouldn't happen
|
||||
}
|
||||
}
|
||||
emit_post_push_imm(emit, vtype, val);
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_native_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
DEBUG_printf("load_const_small_int %d\n", arg);
|
||||
emit_native_pre(emit);
|
||||
if (emit->do_viper_types) {
|
||||
@@ -704,7 +705,7 @@ STATIC void emit_native_load_const_int(emit_t *emit, qstr qst) {
|
||||
DEBUG_printf("load_const_int %s\n", qstr_str(st));
|
||||
// for viper: load integer, check fits in 32 bits
|
||||
emit_native_pre(emit);
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_obj_new_int_from_qstr, qst, REG_ARG_1);
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_load_const_int, qst, REG_ARG_1);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
|
||||
@@ -721,9 +722,13 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
|
||||
// not implemented properly
|
||||
// load a pointer to the asciiz string?
|
||||
assert(0);
|
||||
emit_post_push_imm(emit, VTYPE_PTR, (machine_uint_t)qstr_str(qstr));
|
||||
emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qstr));
|
||||
} else {
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, mp_load_const_str, qstr, REG_ARG_1);
|
||||
if (bytes) {
|
||||
emit_call_with_imm_arg(emit, 0, mp_load_const_bytes, qstr, REG_ARG_1); // TODO need to add function to runtime table
|
||||
} else {
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, mp_load_const_str, qstr, REG_ARG_1);
|
||||
}
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
}
|
||||
@@ -810,7 +815,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
|
||||
vtype_kind_t vtype_lhs, vtype_rhs;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);
|
||||
if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) {
|
||||
emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, mp_obj_subscr, (machine_uint_t)MP_OBJ_SENTINEL, REG_ARG_3);
|
||||
emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, mp_obj_subscr, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
} else {
|
||||
printf("ViperTypeError: can't do subscr of types %d and %d\n", vtype_lhs, vtype_rhs);
|
||||
@@ -917,8 +922,11 @@ STATIC void emit_native_delete_global(emit_t *emit, qstr qstr) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_delete_attr(emit_t *emit, qstr qstr) {
|
||||
// not supported
|
||||
assert(0);
|
||||
vtype_kind_t vtype_base;
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
|
||||
assert(vtype_base == VTYPE_PYOBJ);
|
||||
emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, mp_store_attr, qstr, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete)
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_delete_subscr(emit_t *emit) {
|
||||
@@ -926,7 +934,7 @@ STATIC void emit_native_delete_subscr(emit_t *emit) {
|
||||
emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1); // index, base
|
||||
assert(vtype_index == VTYPE_PYOBJ);
|
||||
assert(vtype_base == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, mp_obj_subscr, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3);
|
||||
emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, mp_obj_subscr, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);
|
||||
}
|
||||
|
||||
STATIC void emit_native_dup_top(emit_t *emit) {
|
||||
@@ -1043,7 +1051,7 @@ STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
|
||||
emit_native_jump(emit, label); // TODO properly
|
||||
emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
|
||||
}
|
||||
|
||||
STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) {
|
||||
@@ -1054,17 +1062,33 @@ STATIC void emit_native_setup_with(emit_t *emit, uint label) {
|
||||
// not supported, or could be with runtime call
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_with_cleanup(emit_t *emit) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_setup_except(emit_t *emit, uint label) {
|
||||
assert(0);
|
||||
emit_native_pre(emit);
|
||||
// need to commit stack because we may jump elsewhere
|
||||
need_stack_settled(emit);
|
||||
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf
|
||||
emit_call(emit, 0, nlr_push); // TODO need to add function to runtime table
|
||||
#if N_X64
|
||||
asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
|
||||
asm_x64_jcc_label(emit->as, JCC_JNZ, label);
|
||||
#elif N_THUMB
|
||||
asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0);
|
||||
asm_thumb_bcc_label(emit->as, THUMB_CC_NE, label);
|
||||
#endif
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_setup_finally(emit_t *emit, uint label) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_end_finally(emit_t *emit) {
|
||||
assert(0);
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_get_iter(emit_t *emit) {
|
||||
@@ -1084,7 +1108,7 @@ STATIC void emit_native_for_iter(emit_t *emit, uint label) {
|
||||
emit_access_stack(emit, 1, &vtype, REG_ARG_1);
|
||||
assert(vtype == VTYPE_PYOBJ);
|
||||
emit_call(emit, MP_F_ITERNEXT, mp_iternext);
|
||||
ASM_MOV_IMM_TO_REG((machine_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1);
|
||||
ASM_MOV_IMM_TO_REG((mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1);
|
||||
#if N_X64
|
||||
asm_x64_cmp_r64_with_r64(emit->as, REG_RET, REG_TEMP1);
|
||||
asm_x64_jcc_label(emit->as, JCC_JE, label);
|
||||
@@ -1104,19 +1128,31 @@ STATIC void emit_native_for_iter_end(emit_t *emit) {
|
||||
|
||||
STATIC void emit_native_pop_block(emit_t *emit) {
|
||||
emit_native_pre(emit);
|
||||
emit_call(emit, 0, nlr_pop); // TODO need to add function to runtime table
|
||||
adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t)));
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_pop_except(emit_t *emit) {
|
||||
assert(0);
|
||||
/*
|
||||
emit_native_pre(emit);
|
||||
emit_call(emit, 0, nlr_pop); // TODO need to add function to runtime table
|
||||
adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t)));
|
||||
emit_post(emit);
|
||||
*/
|
||||
}
|
||||
|
||||
STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
|
||||
assert(vtype == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg(emit, MP_F_UNARY_OP, mp_unary_op, op, REG_ARG_1);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
if (op == MP_UNARY_OP_NOT) {
|
||||
// we need to synthesise this operation
|
||||
assert(0);
|
||||
} else {
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
|
||||
assert(vtype == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg(emit, MP_F_UNARY_OP, mp_unary_op, op, REG_ARG_1);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
@@ -1230,17 +1266,26 @@ STATIC void emit_native_set_add(emit_t *emit, int set_index) {
|
||||
|
||||
STATIC void emit_native_build_slice(emit_t *emit, int n_args) {
|
||||
DEBUG_printf("build_slice %d\n", n_args);
|
||||
assert(n_args == 2);
|
||||
vtype_kind_t vtype_start, vtype_stop;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
|
||||
assert(vtype_start == VTYPE_PYOBJ);
|
||||
assert(vtype_stop == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg3 = step
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
if (n_args == 2) {
|
||||
vtype_kind_t vtype_start, vtype_stop;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
|
||||
assert(vtype_start == VTYPE_PYOBJ);
|
||||
assert(vtype_stop == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (mp_uint_t)mp_const_none, REG_ARG_3); // arg3 = step
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
} else {
|
||||
assert(n_args == 3);
|
||||
vtype_kind_t vtype_start, vtype_stop, vtype_step;
|
||||
emit_pre_pop_reg_reg_reg(emit, &vtype_step, REG_ARG_3, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop, arg3 = step
|
||||
assert(vtype_start == VTYPE_PYOBJ);
|
||||
assert(vtype_stop == VTYPE_PYOBJ);
|
||||
assert(vtype_step == VTYPE_PYOBJ);
|
||||
emit_call(emit, MP_F_NEW_SLICE, mp_obj_new_slice);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) {
|
||||
// TODO this is untested
|
||||
DEBUG_printf("unpack_sequence %d\n", n_args);
|
||||
vtype_kind_t vtype_base;
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
|
||||
@@ -1250,26 +1295,25 @@ STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_unpack_ex(emit_t *emit, int n_left, int n_right) {
|
||||
// TODO this is untested
|
||||
DEBUG_printf("unpack_ex %d %d\n", n_left, n_right);
|
||||
vtype_kind_t vtype_base;
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
|
||||
assert(vtype_base == VTYPE_PYOBJ);
|
||||
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right); // arg3 = dest ptr
|
||||
emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left + n_right, REG_ARG_2); // arg2 = n_left + n_right
|
||||
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr
|
||||
emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right
|
||||
}
|
||||
|
||||
STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
|
||||
// call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them
|
||||
emit_native_pre(emit);
|
||||
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
|
||||
emit_call_with_3_imm_args_and_first_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (machine_uint_t)scope->raw_code, REG_ARG_1, (machine_uint_t)MP_OBJ_NULL, REG_ARG_2, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3);
|
||||
emit_call_with_3_imm_args_and_first_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (mp_uint_t)scope->raw_code, REG_ARG_1, (mp_uint_t)MP_OBJ_NULL, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);
|
||||
} else {
|
||||
vtype_kind_t vtype_def_tuple, vtype_def_dict;
|
||||
emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2);
|
||||
assert(vtype_def_tuple == VTYPE_PYOBJ);
|
||||
assert(vtype_def_dict == VTYPE_PYOBJ);
|
||||
emit_call_with_imm_arg_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (machine_uint_t)scope->raw_code, REG_ARG_1);
|
||||
emit_call_with_imm_arg_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (mp_uint_t)scope->raw_code, REG_ARG_1);
|
||||
}
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
@@ -1365,9 +1409,16 @@ STATIC void emit_native_return_value(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_raise_varargs(emit_t *emit, int n_args) {
|
||||
// call runtime
|
||||
assert(0);
|
||||
assert(n_args == 1);
|
||||
vtype_kind_t vtype_err;
|
||||
emit_pre_pop_reg(emit, &vtype_err, REG_ARG_1); // arg1 = object to raise
|
||||
assert(vtype_err == VTYPE_PYOBJ);
|
||||
emit_call(emit, 0, mp_make_raise_obj); // TODO need to add function to runtime table
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
emit_pre_pop_reg(emit, &vtype_err, REG_ARG_1);
|
||||
emit_call(emit, 0, nlr_jump); // TODO need to add function to runtime table
|
||||
}
|
||||
|
||||
STATIC void emit_native_yield_value(emit_t *emit) {
|
||||
// not supported (for now)
|
||||
assert(0);
|
||||
@@ -1377,6 +1428,21 @@ STATIC void emit_native_yield_from(emit_t *emit) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_start_except_handler(emit_t *emit) {
|
||||
// This instruction follows an nlr_pop, so the stack counter is back to zero, when really
|
||||
// it should be up by a whole nlr_buf_t. We then want to pop the nlr_buf_t here, but save
|
||||
// the first 2 elements, so we can get the thrown value.
|
||||
adjust_stack(emit, 2);
|
||||
vtype_kind_t vtype_nlr;
|
||||
emit_pre_pop_reg(emit, &vtype_nlr, REG_ARG_1); // get the thrown value
|
||||
emit_pre_pop_discard(emit, &vtype_nlr); // discard the linked-list pointer in the nlr_buf
|
||||
emit_post_push_reg_reg_reg(emit, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1); // push the 3 exception items
|
||||
}
|
||||
|
||||
STATIC void emit_native_end_except_handler(emit_t *emit) {
|
||||
adjust_stack(emit, -3); // stack adjust (not sure why it's this much...)
|
||||
}
|
||||
|
||||
const emit_method_table_t EXPORT_FUN(method_table) = {
|
||||
emit_native_set_viper_types,
|
||||
emit_native_start_pass,
|
||||
@@ -1462,6 +1528,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
|
||||
emit_native_raise_varargs,
|
||||
emit_native_yield_value,
|
||||
emit_native_yield_from,
|
||||
|
||||
emit_native_start_except_handler,
|
||||
emit_native_end_except_handler,
|
||||
};
|
||||
|
||||
#endif // (MICROPY_EMIT_X64 && N_X64) || (MICROPY_EMIT_THUMB && N_THUMB)
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -214,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,
|
||||
|
||||
166
py/gc.c
166
py/gc.c
@@ -33,7 +33,6 @@
|
||||
#include "misc.h"
|
||||
#include "gc.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -52,17 +51,17 @@
|
||||
#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;
|
||||
|
||||
// ATB = allocation table byte
|
||||
// 0b00 = FREE -- free block
|
||||
@@ -94,8 +93,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
|
||||
@@ -112,15 +111,15 @@ 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 = " UINT_FMT " 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
|
||||
@@ -131,13 +130,13 @@ void gc_init(void *start, void *end) {
|
||||
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;
|
||||
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;
|
||||
|
||||
// clear ATBs
|
||||
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
|
||||
@@ -173,16 +172,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); \
|
||||
@@ -198,18 +201,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);
|
||||
}
|
||||
}
|
||||
@@ -221,7 +224,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;
|
||||
@@ -231,10 +234,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
|
||||
@@ -254,10 +264,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;
|
||||
@@ -276,9 +290,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();
|
||||
}
|
||||
@@ -291,14 +305,14 @@ void gc_collect_end(void) {
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -335,8 +349,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
|
||||
@@ -349,10 +363,10 @@ 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 (;;) {
|
||||
|
||||
@@ -385,19 +399,20 @@ found:
|
||||
|
||||
// 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) {
|
||||
@@ -412,11 +427,11 @@ found:
|
||||
}
|
||||
|
||||
/*
|
||||
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);
|
||||
}
|
||||
*/
|
||||
@@ -428,10 +443,11 @@ 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) {
|
||||
// free head and all of its tail blocks
|
||||
do {
|
||||
@@ -442,14 +458,14 @@ void gc_free(void *ptr_in) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -463,8 +479,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 {
|
||||
@@ -473,7 +489,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
|
||||
@@ -490,7 +506,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;
|
||||
}
|
||||
@@ -500,7 +516,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)) {
|
||||
@@ -508,7 +524,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) {
|
||||
@@ -516,14 +532,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
|
||||
@@ -546,7 +562,7 @@ 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);
|
||||
}
|
||||
return ptr_in;
|
||||
@@ -555,13 +571,13 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
// 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);
|
||||
|
||||
return ptr_in;
|
||||
}
|
||||
@@ -580,7 +596,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;
|
||||
@@ -597,7 +613,7 @@ void gc_dump_info() {
|
||||
|
||||
void gc_dump_alloc_table(void) {
|
||||
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++) {
|
||||
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % 64 == 0) {
|
||||
printf("\n%04x: ", (uint)bl);
|
||||
}
|
||||
@@ -607,12 +623,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;
|
||||
}
|
||||
@@ -627,23 +643,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;
|
||||
|
||||
21
py/gc.h
21
py/gc.h
@@ -30,25 +30,26 @@ void gc_init(void *start, void *end);
|
||||
// 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);
|
||||
|
||||
108
py/lexer.c
108
py/lexer.c
@@ -32,8 +32,8 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
@@ -50,23 +50,25 @@ struct _mp_lexer_t {
|
||||
|
||||
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;
|
||||
@@ -79,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);
|
||||
@@ -173,7 +175,7 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
return;
|
||||
}
|
||||
|
||||
int advance = 1;
|
||||
mp_uint_t advance = 1;
|
||||
|
||||
if (lex->chr0 == '\n') {
|
||||
// LF is a new line
|
||||
@@ -208,16 +210,16 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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 + MP_ALLOC_LEXEL_INDENT_INC);
|
||||
lex->alloc_indent_level += MP_ALLOC_LEXEL_INDENT_INC;
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -303,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));
|
||||
@@ -318,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);
|
||||
@@ -392,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)) {
|
||||
@@ -461,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);
|
||||
@@ -473,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;
|
||||
@@ -500,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');
|
||||
@@ -531,7 +547,13 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
}
|
||||
}
|
||||
if (c != MP_LEXER_CHAR_EOF) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
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));
|
||||
@@ -606,7 +628,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;
|
||||
@@ -628,7 +650,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;
|
||||
@@ -687,9 +709,19 @@ 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;
|
||||
}
|
||||
}
|
||||
@@ -715,7 +747,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
|
||||
lex->column = 1;
|
||||
lex->emit_dent = 0;
|
||||
lex->nested_bracket_level = 0;
|
||||
lex->alloc_indent_level = MP_ALLOC_LEXER_INDENT_INIT;
|
||||
lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT;
|
||||
lex->num_indent_level = 1;
|
||||
lex->indent_level = m_new_maybe(uint16_t, lex->alloc_indent_level);
|
||||
vstr_init(&lex->vstr, 32);
|
||||
|
||||
10
py/lexer.h
10
py/lexer.h
@@ -131,12 +131,12 @@ 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
|
||||
@@ -151,7 +151,7 @@ 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_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);
|
||||
@@ -176,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;
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
* 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
|
||||
@@ -51,7 +51,7 @@ 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;
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if MICROPY_ENABLE_LEXER_UNIX
|
||||
#if MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -81,4 +81,4 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
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);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_LEXER_UNIX
|
||||
#endif // MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
@@ -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,8 +28,8 @@
|
||||
#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
|
||||
|
||||
6
py/map.c
6
py/map.c
@@ -27,8 +27,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -167,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;
|
||||
@@ -270,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;
|
||||
|
||||
28
py/misc.h
28
py/misc.h
@@ -82,22 +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 *********************************************/
|
||||
|
||||
@@ -161,4 +169,18 @@ 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)
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#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 },
|
||||
@@ -40,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,
|
||||
},
|
||||
};
|
||||
@@ -51,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
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
|
||||
#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
|
||||
|
||||
// These are defined in modmath.c
|
||||
extern const mp_obj_float_t mp_math_e_obj;
|
||||
@@ -142,8 +142,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,
|
||||
},
|
||||
};
|
||||
@@ -154,4 +154,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
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#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) },
|
||||
@@ -42,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,
|
||||
},
|
||||
};
|
||||
@@ -54,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
|
||||
|
||||
30
py/modgc.c
30
py/modgc.c
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -35,11 +35,17 @@
|
||||
#include "objstr.h"
|
||||
#include "gc.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_GC && MICROPY_ENABLE_GC
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
|
||||
extern uint gc_collected;
|
||||
|
||||
STATIC mp_obj_t py_gc_collect(void) {
|
||||
gc_collect();
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)gc_collected);
|
||||
#else
|
||||
return mp_const_none;
|
||||
#endif
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||
|
||||
@@ -55,11 +61,27 @@ STATIC mp_obj_t gc_enable(void) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
||||
|
||||
STATIC mp_obj_t gc_mem_free(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)info.free);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free);
|
||||
|
||||
STATIC mp_obj_t gc_mem_alloc(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)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 = {
|
||||
@@ -67,8 +89,8 @@ STATIC const mp_obj_dict_t mp_module_gc_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.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,
|
||||
},
|
||||
};
|
||||
|
||||
25
py/modio.c
25
py/modio.c
@@ -24,21 +24,32 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#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 = {
|
||||
@@ -46,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,
|
||||
};
|
||||
|
||||
|
||||
13
py/modmath.c
13
py/modmath.c
@@ -26,13 +26,13 @@
|
||||
|
||||
#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
|
||||
|
||||
//TODO: Change macros to check for overflow and raise OverflowError or RangeError
|
||||
#define MATH_FUN_1(py_name, c_name) \
|
||||
@@ -48,7 +48,7 @@
|
||||
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
|
||||
@@ -151,6 +151,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 },
|
||||
@@ -171,8 +172,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,
|
||||
},
|
||||
};
|
||||
@@ -183,4 +184,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
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -35,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((mp_int_t)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((mp_int_t)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((mp_int_t)m_get_peak_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);
|
||||
@@ -65,8 +65,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,
|
||||
},
|
||||
};
|
||||
|
||||
110
py/modstruct.c
110
py/modstruct.c
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -26,16 +27,33 @@
|
||||
|
||||
#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;
|
||||
@@ -56,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;
|
||||
@@ -89,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;
|
||||
@@ -106,7 +170,29 @@ 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;
|
||||
}
|
||||
@@ -124,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,
|
||||
},
|
||||
};
|
||||
|
||||
37
py/modsys.c
37
py/modsys.c
@@ -24,8 +24,10 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -33,8 +35,10 @@
|
||||
#include "objlist.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
|
||||
// These should be implemented by ports, specific types don't matter,
|
||||
// only addresses.
|
||||
@@ -44,6 +48,8 @@ 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 mp_obj_int_t mp_maxsize_obj;
|
||||
|
||||
mp_obj_list_t mp_sys_path_obj;
|
||||
mp_obj_list_t mp_sys_argv_obj;
|
||||
#define I(n) MP_OBJ_NEW_SMALL_INT(n)
|
||||
@@ -51,6 +57,9 @@ mp_obj_list_t mp_sys_argv_obj;
|
||||
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
|
||||
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) },
|
||||
@@ -59,17 +68,33 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
|
||||
{ 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
|
||||
#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_EXIT
|
||||
|
||||
#if MICROPY_PY_SYS_EXIT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_exit), (mp_obj_t)&mp_sys_exit_obj },
|
||||
#endif
|
||||
|
||||
#if MICROPY_MOD_SYS_STDFILES
|
||||
#if MICROPY_PY_SYS_STDFILES
|
||||
{ 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 },
|
||||
@@ -81,8 +106,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,
|
||||
},
|
||||
};
|
||||
|
||||
293
py/mpconfig.h
293
py/mpconfig.h
@@ -37,43 +37,54 @@
|
||||
/* Memory allocation policy */
|
||||
|
||||
// Initial amount for lexer indentation level
|
||||
#ifndef MP_ALLOC_LEXER_INDENT_INIT
|
||||
#define MP_ALLOC_LEXER_INDENT_INIT (10)
|
||||
#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT
|
||||
#define MICROPY_ALLOC_LEXER_INDENT_INIT (10)
|
||||
#endif
|
||||
|
||||
// Increment for lexer indentation level
|
||||
#ifndef MP_ALLOC_LEXEL_INDENT_INC
|
||||
#define MP_ALLOC_LEXEL_INDENT_INC (8)
|
||||
#ifndef MICROPY_ALLOC_LEXEL_INDENT_INC
|
||||
#define MICROPY_ALLOC_LEXEL_INDENT_INC (8)
|
||||
#endif
|
||||
|
||||
// Initial amount for parse rule stack
|
||||
#ifndef MP_ALLOC_PARSE_RULE_INIT
|
||||
#define MP_ALLOC_PARSE_RULE_INIT (64)
|
||||
#ifndef MICROPY_ALLOC_PARSE_RULE_INIT
|
||||
#define MICROPY_ALLOC_PARSE_RULE_INIT (64)
|
||||
#endif
|
||||
|
||||
// Increment for parse rule stack
|
||||
#ifndef MP_ALLOC_PARSE_RULE_INC
|
||||
#define MP_ALLOC_PARSE_RULE_INC (16)
|
||||
#ifndef MICROPY_ALLOC_PARSE_RULE_INC
|
||||
#define MICROPY_ALLOC_PARSE_RULE_INC (16)
|
||||
#endif
|
||||
|
||||
// Initial amount for parse result stack
|
||||
#ifndef MP_ALLOC_PARSE_RESULT_INIT
|
||||
#define MP_ALLOC_PARSE_RESULT_INIT (32)
|
||||
#ifndef MICROPY_ALLOC_PARSE_RESULT_INIT
|
||||
#define MICROPY_ALLOC_PARSE_RESULT_INIT (32)
|
||||
#endif
|
||||
|
||||
// Increment for parse result stack
|
||||
#ifndef MP_ALLOC_PARSE_RESULT_INC
|
||||
#define MP_ALLOC_PARSE_RESULT_INC (16)
|
||||
#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 MP_ALLOC_SCOPE_ID_INIT
|
||||
#define MP_ALLOC_SCOPE_ID_INIT (4)
|
||||
#ifndef MICROPY_ALLOC_SCOPE_ID_INIT
|
||||
#define MICROPY_ALLOC_SCOPE_ID_INIT (4)
|
||||
#endif
|
||||
|
||||
// Increment for ids in a scope
|
||||
#ifndef MP_ALLOC_SCOPE_ID_INC
|
||||
#define MP_ALLOC_SCOPE_ID_INC (6)
|
||||
#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
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -100,6 +111,14 @@
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Compiler configuration */
|
||||
|
||||
// Whether to enable constant optimisation; id = const(value)
|
||||
#ifndef MICROPY_COMP_CONST
|
||||
#define MICROPY_COMP_CONST (1)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Internal debugging stuff */
|
||||
|
||||
@@ -117,13 +136,17 @@
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Fine control over Python features */
|
||||
/* Optimisations */
|
||||
|
||||
// Whether to enable constant optimisation; id = const(value)
|
||||
#ifndef MICROPY_ENABLE_CONST
|
||||
#define MICROPY_ENABLE_CONST (1)
|
||||
// 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
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
@@ -134,14 +157,20 @@
|
||||
#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 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
|
||||
@@ -189,76 +218,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 "gc" module
|
||||
#ifndef MICROPY_ENABLE_MOD_GC
|
||||
#define MICROPY_ENABLE_MOD_GC (1)
|
||||
#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
|
||||
|
||||
// sys.exit() availability
|
||||
#ifndef MICROPY_MOD_SYS_EXIT
|
||||
#define MICROPY_MOD_SYS_EXIT (0)
|
||||
#endif
|
||||
|
||||
// sys.{stdin,stdout,stderr} availability
|
||||
#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 frozenset object
|
||||
#ifndef MICROPY_ENABLE_FROZENSET
|
||||
#define MICROPY_ENABLE_FROZENSET (0)
|
||||
#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
|
||||
@@ -269,36 +241,138 @@ 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)
|
||||
#endif
|
||||
|
||||
// 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 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
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -312,8 +386,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?
|
||||
@@ -324,14 +398,14 @@ typedef double mp_float_t;
|
||||
#define MP_ENDIANNESS_LITTLE (0)
|
||||
#endif
|
||||
|
||||
// printf format spec to use for machine_int_t and friends
|
||||
// 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
|
||||
@@ -341,3 +415,8 @@ typedef double mp_float_t;
|
||||
#ifndef NORETURN
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
// Modifier for weak functions
|
||||
#ifndef MP_WEAK
|
||||
#define MP_WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
114
py/mpz.c
114
py/mpz.c
@@ -30,8 +30,8 @@
|
||||
#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
|
||||
@@ -207,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
|
||||
@@ -321,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;
|
||||
@@ -472,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;
|
||||
@@ -498,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;
|
||||
@@ -564,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;
|
||||
@@ -674,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;
|
||||
@@ -800,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) {
|
||||
@@ -815,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) {
|
||||
@@ -898,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
|
||||
@@ -1172,12 +1214,12 @@ 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;
|
||||
mp_int_t mpz_as_int(const mpz_t *i) {
|
||||
mp_int_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
machine_int_t oldval = val;
|
||||
mp_int_t oldval = val;
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
if (val < oldval) {
|
||||
// overflow, return +/- "infinity"
|
||||
@@ -1199,12 +1241,12 @@ machine_int_t mpz_as_int(const mpz_t *i) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
mp_int_t oldval = val;
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
if (val < oldval) {
|
||||
// overflow
|
||||
@@ -1220,7 +1262,7 @@ bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#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;
|
||||
|
||||
28
py/mpz.h
28
py/mpz.h
@@ -29,27 +29,27 @@ 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);
|
||||
@@ -57,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);
|
||||
|
||||
@@ -79,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);
|
||||
@@ -96,9 +96,9 @@ 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_as_int(const mpz_t *z);
|
||||
bool mpz_as_int_checked(const mpz_t *z, mp_int_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);
|
||||
|
||||
3
py/nlr.h
3
py/nlr.h
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <limits.h>
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct _nlr_buf_t nlr_buf_t;
|
||||
struct _nlr_buf_t {
|
||||
@@ -44,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)
|
||||
|
||||
@@ -24,19 +24,21 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__thumb2__) && !MICROPY_NLR_SETJMP
|
||||
/* thumb callee save: bx, bp, sp, r12, r14, r14, r15 */
|
||||
#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
|
||||
@@ -64,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
|
||||
@@ -80,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
|
||||
|
||||
@@ -32,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
|
||||
|
||||
49
py/obj.c
49
py/obj.c
@@ -35,6 +35,7 @@
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "stackctrl.h"
|
||||
|
||||
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
@@ -59,6 +60,8 @@ 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)");
|
||||
@@ -80,7 +83,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);
|
||||
@@ -122,7 +125,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;
|
||||
}
|
||||
}
|
||||
@@ -142,7 +145,7 @@ 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) {
|
||||
@@ -152,13 +155,13 @@ machine_int_t mp_obj_hash(mp_obj_t 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;
|
||||
return (mp_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_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
|
||||
@@ -212,7 +215,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;
|
||||
}
|
||||
}
|
||||
@@ -222,7 +225,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].
|
||||
@@ -241,8 +244,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) {
|
||||
@@ -257,7 +260,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;
|
||||
@@ -274,6 +277,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;
|
||||
@@ -297,6 +301,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)) {
|
||||
@@ -325,8 +330,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)) {
|
||||
@@ -352,17 +357,17 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index,
|
||||
|
||||
// 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_int_t)mp_obj_str_get_len(o_in));
|
||||
} else {
|
||||
mp_obj_type_t *type = mp_obj_get_type(o_in);
|
||||
if (type->unary_op != NULL) {
|
||||
mp_obj_t val = type->unary_op(MP_UNARY_OP_LEN, o_in);
|
||||
// TODO: Here's the case of having MP_OBJ_NOT_SUPPORTED is confusing
|
||||
if (val == MP_OBJ_NOT_SUPPORTED) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
return val;
|
||||
return type->unary_op(MP_UNARY_OP_LEN, o_in);
|
||||
} else {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
@@ -373,7 +378,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?
|
||||
|
||||
143
py/obj.h
143
py/obj.h
@@ -35,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)
|
||||
|
||||
@@ -52,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.
|
||||
@@ -63,35 +57,29 @@ 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_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 a string, use below macro 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_SMALL_INT_VALUE(o) (((mp_small_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_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
|
||||
@@ -144,10 +132,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;
|
||||
|
||||
@@ -158,7 +146,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);
|
||||
@@ -172,12 +160,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);
|
||||
@@ -223,7 +211,7 @@ typedef struct _mp_buffer_info_t {
|
||||
//int ver; // ?
|
||||
|
||||
void *buf;
|
||||
machine_int_t len; // in bytes
|
||||
mp_int_t len; // in bytes
|
||||
int typecode; // as per binary.h
|
||||
|
||||
// Rationale: to load arbitrary-sized sprites directly to LCD
|
||||
@@ -234,7 +222,7 @@ 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);
|
||||
@@ -243,9 +231,10 @@ void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
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);
|
||||
mp_int_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
|
||||
mp_int_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
|
||||
// add seek() ?
|
||||
int is_bytes : 1;
|
||||
} mp_stream_p_t;
|
||||
|
||||
struct _mp_obj_type_t {
|
||||
@@ -255,15 +244,15 @@ 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 MP_OBJ_NOT_SUPPORTED if op not supported
|
||||
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NOT_SUPPORTED 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_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args)
|
||||
@@ -321,6 +310,7 @@ 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;
|
||||
|
||||
// Exceptions
|
||||
extern const mp_obj_type_t mp_type_BaseException;
|
||||
@@ -345,6 +335,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;
|
||||
@@ -369,13 +360,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_qstr(qstr qst);
|
||||
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
|
||||
@@ -384,7 +375,7 @@ 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_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
|
||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
||||
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);
|
||||
@@ -410,47 +401,47 @@ 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_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)
|
||||
@@ -458,8 +449,8 @@ 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);
|
||||
|
||||
@@ -472,26 +463,27 @@ 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_NOT_SUPPORTED
|
||||
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_NOT_SUPPORTED
|
||||
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_int_t mp_obj_tuple_hash(mp_obj_t self_in);
|
||||
|
||||
// list
|
||||
struct _mp_obj_list_t;
|
||||
@@ -509,6 +501,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);
|
||||
@@ -517,7 +510,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);
|
||||
@@ -536,9 +529,7 @@ typedef struct _mp_obj_fun_native_t { // need this so we can define const object
|
||||
// such functions won't be able to access the global scope, but that's probably okay
|
||||
} mp_obj_fun_native_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);
|
||||
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);
|
||||
@@ -563,14 +554,25 @@ 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 mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end);
|
||||
#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) \
|
||||
@@ -578,3 +580,8 @@ mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value);
|
||||
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));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -36,13 +37,15 @@
|
||||
#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;
|
||||
|
||||
@@ -57,7 +60,7 @@ STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *en
|
||||
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);
|
||||
mp_str_print_quoted(print, env, o->items, o->len, true);
|
||||
} else {
|
||||
print(env, "array('%c'", o->typecode);
|
||||
if (o->len > 0) {
|
||||
@@ -139,7 +142,7 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,26 +168,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 (!mp_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) {
|
||||
@@ -199,7 +206,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);
|
||||
@@ -278,7 +285,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) {
|
||||
@@ -305,3 +312,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
|
||||
|
||||
@@ -61,7 +61,7 @@ STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -74,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_int_t)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 = {
|
||||
|
||||
@@ -37,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;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -123,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,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);
|
||||
}
|
||||
|
||||
138
py/objdict.c
138
py/objdict.c
@@ -40,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;
|
||||
@@ -61,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;
|
||||
}
|
||||
|
||||
@@ -102,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((mp_int_t)self->map.used);
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,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)) {
|
||||
@@ -140,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,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++) {
|
||||
@@ -348,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);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -393,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 {
|
||||
@@ -463,13 +473,13 @@ 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 MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
if (op != MP_BINARY_OP_IN) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
return dict_binary_op(op, o->dict, rhs_in);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -36,7 +36,7 @@
|
||||
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);
|
||||
@@ -45,7 +45,7 @@ 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 ARRAY_SIZE(enumerate_make_new_args)
|
||||
#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) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "objtype.h"
|
||||
#include "runtime.h"
|
||||
#include "runtime0.h"
|
||||
#include "gc.h"
|
||||
|
||||
typedef struct _mp_obj_exception_t {
|
||||
mp_obj_base_t base;
|
||||
@@ -120,12 +121,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) \
|
||||
@@ -142,9 +158,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)
|
||||
@@ -168,11 +184,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)
|
||||
@@ -266,7 +284,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);
|
||||
}
|
||||
}
|
||||
@@ -317,19 +335,26 @@ 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) {
|
||||
#if MICROPY_ENABLE_GC
|
||||
if (gc_is_locked()) {
|
||||
// We can't allocate memory, so don't bother to try
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#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"
|
||||
@@ -96,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 MP_OBJ_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);
|
||||
}
|
||||
}
|
||||
@@ -165,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
|
||||
|
||||
326
py/objfun.c
326
py/objfun.c
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -27,7 +28,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "bc.h"
|
||||
#include "stackctrl.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -58,7 +59,7 @@ STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
// we don't even need to check for 2nd arg type.
|
||||
return MP_BOOL(lhs_in == rhs_in);
|
||||
}
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
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) {
|
||||
@@ -153,8 +154,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);
|
||||
}
|
||||
@@ -193,66 +194,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, uint n_args, uint 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
|
||||
|
||||
@@ -262,57 +231,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 (uint 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 (uint 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++) {
|
||||
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
||||
for (uint 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;
|
||||
}
|
||||
}
|
||||
@@ -323,43 +288,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 (uint 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) {
|
||||
@@ -367,20 +336,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 (uint n_local = *ip++; n_local > 0; n_local--) {
|
||||
uint 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
|
||||
uint 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_bytecode(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 (uint 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
|
||||
@@ -398,7 +468,7 @@ const mp_obj_type_t mp_type_fun_bc = {
|
||||
.binary_op = 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) {
|
||||
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, mp_obj_t def_kw_args, const byte *code) {
|
||||
uint n_def_args = 0;
|
||||
uint n_extra_args = 0;
|
||||
mp_obj_tuple_t *def_args = def_args_in;
|
||||
@@ -407,10 +477,7 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
|
||||
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);
|
||||
@@ -420,18 +487,15 @@ 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;
|
||||
}
|
||||
@@ -445,13 +509,13 @@ typedef struct _mp_obj_fun_asm_t {
|
||||
void *fun;
|
||||
} 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);
|
||||
@@ -464,42 +528,42 @@ 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);
|
||||
}
|
||||
|
||||
@@ -508,7 +572,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
machine_uint_t ret;
|
||||
mp_uint_t ret;
|
||||
if (n_args == 0) {
|
||||
ret = ((inline_asm_fun_0_t)self->fun)();
|
||||
} else if (n_args == 1) {
|
||||
|
||||
23
py/objfun.h
23
py/objfun.h
@@ -26,14 +26,19 @@
|
||||
|
||||
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;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -45,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 = {
|
||||
@@ -78,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_bytecode2(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) {
|
||||
@@ -130,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:
|
||||
@@ -250,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_bytecode2 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;
|
||||
}
|
||||
|
||||
51
py/objint.c
51
py/objint.c
@@ -35,12 +35,13 @@
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "parsenum.h"
|
||||
#include "smallint.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
@@ -53,16 +54,20 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
|
||||
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(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((mp_int_t)(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]));
|
||||
}
|
||||
|
||||
@@ -80,7 +85,7 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
|
||||
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;
|
||||
@@ -96,7 +101,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[] = {
|
||||
@@ -122,14 +127,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)) {
|
||||
@@ -139,8 +144,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.
|
||||
@@ -149,7 +154,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;
|
||||
}
|
||||
@@ -216,7 +221,7 @@ bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||
|
||||
// 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
|
||||
@@ -225,7 +230,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_qstr(qstr qst) {
|
||||
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;
|
||||
}
|
||||
@@ -236,7 +241,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) {
|
||||
@@ -246,23 +251,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);
|
||||
}
|
||||
@@ -285,7 +290,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_
|
||||
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
|
||||
@@ -299,7 +304,7 @@ 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;
|
||||
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;
|
||||
}
|
||||
@@ -311,7 +316,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;
|
||||
@@ -321,7 +326,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ typedef struct _mp_obj_int_t {
|
||||
} mp_obj_int_t;
|
||||
|
||||
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
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);
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
int base, const char *prefix, char base_char, char comma);
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -33,6 +34,7 @@
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "smallint.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "runtime0.h"
|
||||
@@ -48,6 +50,11 @@
|
||||
#define SUFFIX ""
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_MAXSIZE
|
||||
// Export value for sys.maxsize
|
||||
const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, INT_MAX};
|
||||
#endif
|
||||
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
|
||||
@@ -63,7 +70,7 @@ mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
||||
case MP_UNARY_OP_POSITIVE: return o_in;
|
||||
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val);
|
||||
case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +83,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
} else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
|
||||
lhs_val = ((mp_obj_int_t*)lhs_in)->val;
|
||||
} else {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
if (MP_OBJ_IS_SMALL_INT(rhs_in)) {
|
||||
@@ -134,18 +141,18 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return MP_BOOL(lhs_val == rhs_val);
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return mp_obj_new_int_from_ll(value);
|
||||
}
|
||||
|
||||
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
|
||||
// than word size, which totals 2 bits less for unsigned numbers.
|
||||
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
|
||||
@@ -161,36 +168,32 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
|
||||
const char *s = qstr_str(qst);
|
||||
long long v;
|
||||
char *end;
|
||||
// TODO: this doesn't handle Python hacked 0o octal syntax
|
||||
v = strtoll(s, &end, 0);
|
||||
if (*end != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
|
||||
}
|
||||
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
|
||||
// TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated
|
||||
// TODO check overflow
|
||||
mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
|
||||
o->base.type = &mp_type_int;
|
||||
o->val = v;
|
||||
char *endptr;
|
||||
o->val = strtoll(*str, &endptr, base);
|
||||
*str = endptr;
|
||||
return o;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
} else {
|
||||
mp_obj_int_t *self = self_in;
|
||||
const mp_obj_int_t *self = self_in;
|
||||
return self->val;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// TODO: Check overflow
|
||||
return mp_obj_int_get(self_in);
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "qstr.h"
|
||||
#include "parsenumbase.h"
|
||||
#include "obj.h"
|
||||
#include "smallint.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "runtime0.h"
|
||||
@@ -42,6 +43,26 @@
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
|
||||
|
||||
#if MICROPY_PY_SYS_MAXSIZE
|
||||
// Export value for sys.maxsize
|
||||
#define DIG_MASK ((1 << MPZ_DIG_SIZE) - 1)
|
||||
STATIC const mpz_dig_t maxsize_dig[MPZ_NUM_DIG_FOR_INT] = {
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK,
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,
|
||||
#if (INT_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 4) & DIG_MASK,
|
||||
// (INT_MAX >> MPZ_DIG_SIZE * 5) & DIG_MASK,
|
||||
#endif
|
||||
};
|
||||
const mp_obj_int_t mp_maxsize_obj = {
|
||||
{&mp_type_int},
|
||||
{.fixed_dig = 1, .len = MPZ_NUM_DIG_FOR_INT, .alloc = MPZ_NUM_DIG_FOR_INT, .dig = (mpz_dig_t*)maxsize_dig}
|
||||
};
|
||||
#undef DIG_MASK
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
|
||||
mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
|
||||
o->base.type = &mp_type_int;
|
||||
@@ -58,10 +79,10 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
|
||||
// formatted size will be in *fmt_size.
|
||||
//
|
||||
// This particular routine should only be called for the mpz representation of the int.
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
|
||||
int base, const char *prefix, char base_char, char comma) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
|
||||
mp_obj_int_t *self = self_in;
|
||||
const mp_obj_int_t *self = self_in;
|
||||
|
||||
uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma);
|
||||
if (needed_size > *buf_size) {
|
||||
@@ -90,7 +111,7 @@ mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
||||
case MP_UNARY_OP_POSITIVE: return o_in;
|
||||
case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return o2; }
|
||||
case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return o2; }
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +129,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
zlhs = &((mp_obj_int_t*)lhs_in)->mpz;
|
||||
} else {
|
||||
// unsupported type
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
// if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)
|
||||
@@ -117,11 +138,13 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
zrhs = &z_int;
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
|
||||
zrhs = &((mp_obj_int_t*)rhs_in)->mpz;
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_float)) {
|
||||
return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
|
||||
return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
// delegate to generic function to check for extra cases
|
||||
@@ -129,7 +152,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
}
|
||||
|
||||
if (0) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {
|
||||
mp_float_t flhs = mpz_as_float(zlhs);
|
||||
mp_float_t frhs = mpz_as_float(zrhs);
|
||||
@@ -195,7 +218,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
case MP_BINARY_OP_RSHIFT:
|
||||
case MP_BINARY_OP_INPLACE_RSHIFT: {
|
||||
// TODO check conversion overflow
|
||||
machine_int_t irhs = mpz_as_int(zrhs);
|
||||
mp_int_t irhs = mpz_as_int(zrhs);
|
||||
if (irhs < 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
|
||||
}
|
||||
@@ -213,7 +236,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
break;
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -233,13 +256,13 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return MP_BOOL(cmp == 0);
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return mp_obj_new_int_from_ll(value);
|
||||
@@ -251,7 +274,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
|
||||
return o;
|
||||
}
|
||||
|
||||
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
|
||||
// than word size, which totals 2 bits less for unsigned numbers.
|
||||
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
|
||||
@@ -260,36 +283,28 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
return mp_obj_new_int_from_ll(value);
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
|
||||
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
|
||||
mp_obj_int_t *o = mp_obj_int_new_mpz();
|
||||
uint len;
|
||||
const char* str = (const char*)qstr_data(qst, &len);
|
||||
int base = 0;
|
||||
int skip = mp_parse_num_base(str, len, &base);
|
||||
str += skip;
|
||||
len -= skip;
|
||||
uint n = mpz_set_from_str(&o->mpz, str, len, false, base);
|
||||
if (n != len) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
|
||||
}
|
||||
uint n = mpz_set_from_str(&o->mpz, *str, len, neg, base);
|
||||
*str += n;
|
||||
return o;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
} else {
|
||||
mp_obj_int_t *self = self_in;
|
||||
const mp_obj_int_t *self = self_in;
|
||||
return mpz_as_int(&self->mpz);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
} else {
|
||||
mp_obj_int_t *self = self_in;
|
||||
machine_int_t value;
|
||||
const mp_obj_int_t *self = self_in;
|
||||
mp_int_t value;
|
||||
if (mpz_as_int_checked(&self->mpz, &value)) {
|
||||
return value;
|
||||
} else {
|
||||
@@ -299,7 +314,7 @@ machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
|
||||
65
py/objlist.c
65
py/objlist.c
@@ -103,7 +103,7 @@ STATIC mp_obj_t list_unary_op(int op, mp_obj_t self_in) {
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(self->len != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_ADD: {
|
||||
if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
mp_obj_list_t *p = rhs;
|
||||
mp_obj_list_t *s = list_new(o->len + p->len);
|
||||
@@ -121,15 +121,15 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
}
|
||||
case MP_BINARY_OP_INPLACE_ADD: {
|
||||
if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
list_extend(lhs, rhs);
|
||||
return o;
|
||||
}
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
machine_int_t n;
|
||||
mp_int_t n;
|
||||
if (!mp_obj_get_int_maybe(rhs, &n)) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
mp_obj_list_t *s = list_new(o->len * n);
|
||||
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
||||
@@ -143,25 +143,25 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
return MP_BOOL(list_cmp_helper(op, lhs, rhs));
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
if (value == MP_OBJ_NULL) {
|
||||
// delete
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
mp_obj_list_t *self = self_in;
|
||||
machine_uint_t start, stop;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
|
||||
mp_bound_slice_t slice;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int len_adj = start - stop;
|
||||
int len_adj = slice.start - slice.stop;
|
||||
//printf("Len adj: %d\n", len_adj);
|
||||
assert(len_adj <= 0);
|
||||
mp_seq_replace_slice_no_grow(self->items, self->len, start, stop, self->items/*NULL*/, 0, mp_obj_t);
|
||||
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, mp_obj_t);
|
||||
// Clear "freed" elements at the end of list
|
||||
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
|
||||
self->len += len_adj;
|
||||
@@ -174,37 +174,48 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
mp_obj_list_t *self = self_in;
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
machine_uint_t start, stop;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
|
||||
assert(0);
|
||||
mp_bound_slice_t slice;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
|
||||
return mp_seq_extract_slice(self->len, self->items, &slice);
|
||||
}
|
||||
mp_obj_list_t *res = list_new(stop - start);
|
||||
mp_seq_copy(res->items, self->items + start, res->len, mp_obj_t);
|
||||
mp_obj_list_t *res = list_new(slice.stop - slice.start);
|
||||
mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
uint index_val = mp_get_index(self->base.type, self->len, index, false);
|
||||
return self->items[index_val];
|
||||
} else {
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
mp_obj_list_t *self = self_in;
|
||||
assert(MP_OBJ_IS_TYPE(value, &mp_type_list));
|
||||
mp_obj_list_t *slice = value;
|
||||
machine_uint_t start, stop;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
|
||||
mp_bound_slice_t slice_out;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {
|
||||
assert(0);
|
||||
}
|
||||
int len_adj = slice->len - (stop - start);
|
||||
int len_adj = slice->len - (slice_out.stop - slice_out.start);
|
||||
//printf("Len adj: %d\n", len_adj);
|
||||
assert(len_adj <= 0);
|
||||
mp_seq_replace_slice_no_grow(self->items, self->len, start, stop, slice->items, slice->len, mp_obj_t);
|
||||
// Clear "freed" elements at the end of list
|
||||
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
|
||||
if (len_adj > 0) {
|
||||
if (self->len + len_adj > self->alloc) {
|
||||
// TODO: Might optimize memory copies here by checking if block can
|
||||
// be grown inplace or not
|
||||
self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj);
|
||||
self->alloc = self->len + len_adj;
|
||||
}
|
||||
mp_seq_replace_slice_grow_inplace(self->items, self->len,
|
||||
slice_out.start, slice_out.stop, slice->items, slice->len, len_adj, mp_obj_t);
|
||||
} else {
|
||||
mp_seq_replace_slice_no_grow(self->items, self->len,
|
||||
slice_out.start, slice_out.stop, slice->items, slice->len, mp_obj_t);
|
||||
// Clear "freed" elements at the end of list
|
||||
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
|
||||
// TODO: apply allocation policy re: alloc_size
|
||||
}
|
||||
self->len += len_adj;
|
||||
// TODO: apply allocation policy re: alloc_size
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
@@ -477,7 +488,7 @@ void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
typedef struct _mp_obj_list_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_list_t *list;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_list_it_t;
|
||||
|
||||
mp_obj_t list_it_iternext(mp_obj_t self_in) {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
typedef struct _mp_obj_list_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t alloc;
|
||||
machine_uint_t len;
|
||||
mp_uint_t alloc;
|
||||
mp_uint_t len;
|
||||
mp_obj_t *items;
|
||||
} mp_obj_list_t;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
typedef struct _mp_obj_map_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t n_iters;
|
||||
mp_uint_t n_iters;
|
||||
mp_obj_t fun;
|
||||
mp_obj_t iters[];
|
||||
} mp_obj_map_t;
|
||||
@@ -56,10 +56,6 @@ STATIC mp_obj_t map_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t map_getiter(mp_obj_t self_in) {
|
||||
return self_in;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t map_iternext(mp_obj_t self_in) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_map));
|
||||
mp_obj_map_t *self = self_in;
|
||||
@@ -80,6 +76,6 @@ const mp_obj_type_t mp_type_map = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_map,
|
||||
.make_new = map_make_new,
|
||||
.getiter = map_getiter,
|
||||
.getiter = mp_identity,
|
||||
.iternext = map_iternext,
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -33,7 +34,7 @@
|
||||
#include "obj.h"
|
||||
#include "objtuple.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#if MICROPY_PY_COLLECTIONS
|
||||
|
||||
typedef struct _mp_obj_namedtuple_type_t {
|
||||
mp_obj_type_t base;
|
||||
@@ -173,4 +174,4 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type);
|
||||
|
||||
#endif // MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#endif // MICROPY_PY_COLLECTIONS
|
||||
|
||||
@@ -44,7 +44,7 @@ STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env
|
||||
STATIC mp_obj_t none_unary_op(int op, mp_obj_t o_in) {
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return mp_const_false;
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
|
||||
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
|
||||
typedef struct _mp_obj_object_t {
|
||||
mp_obj_base_t base;
|
||||
} mp_obj_object_t;
|
||||
@@ -47,8 +49,35 @@ STATIC mp_obj_t object_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
|
||||
return o;
|
||||
}
|
||||
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
STATIC mp_obj_t object___init__(mp_obj_t self) {
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__);
|
||||
|
||||
STATIC mp_obj_t object___new__(mp_obj_t cls) {
|
||||
mp_obj_t o = MP_OBJ_SENTINEL;
|
||||
mp_obj_t res = instance_make_new(cls, 1, 0, &o);
|
||||
return res;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);
|
||||
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, (const mp_obj_t)&object___new___fun_obj);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t object_locals_dict_table[] = {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&object___init___obj },
|
||||
#endif
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___new__), (mp_obj_t)&object___new___obj },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t mp_type_object = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_object,
|
||||
.make_new = object_make_new,
|
||||
.locals_dict = (mp_obj_t)&object_locals_dict,
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_PROPERTY
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
|
||||
typedef struct _mp_obj_property_t {
|
||||
mp_obj_base_t base;
|
||||
@@ -115,4 +115,4 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) {
|
||||
return self->proxy;
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_PROPERTY
|
||||
#endif // MICROPY_PY_BUILTINS_PROPERTY
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
typedef struct _mp_obj_range_it_t {
|
||||
mp_obj_base_t base;
|
||||
// TODO make these values generic objects or something
|
||||
machine_int_t cur;
|
||||
machine_int_t stop;
|
||||
machine_int_t step;
|
||||
mp_int_t cur;
|
||||
mp_int_t stop;
|
||||
mp_int_t step;
|
||||
} mp_obj_range_it_t;
|
||||
|
||||
STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) {
|
||||
@@ -77,9 +77,9 @@ mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step) {
|
||||
typedef struct _mp_obj_range_t {
|
||||
mp_obj_base_t base;
|
||||
// TODO make these values generic objects or something
|
||||
machine_int_t start;
|
||||
machine_int_t stop;
|
||||
machine_int_t step;
|
||||
mp_int_t start;
|
||||
mp_int_t stop;
|
||||
mp_int_t step;
|
||||
} mp_obj_range_t;
|
||||
|
||||
STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
|
||||
32
py/objset.c
32
py/objset.c
@@ -37,6 +37,8 @@
|
||||
#include "runtime0.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
|
||||
typedef struct _mp_obj_set_t {
|
||||
mp_obj_base_t base;
|
||||
mp_set_t set;
|
||||
@@ -45,20 +47,20 @@ typedef struct _mp_obj_set_t {
|
||||
typedef struct _mp_obj_set_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_set_t *set;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_set_it_t;
|
||||
|
||||
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in);
|
||||
|
||||
STATIC bool is_set_or_frozenset(mp_obj_t o) {
|
||||
return MP_OBJ_IS_TYPE(o, &mp_type_set)
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
|| MP_OBJ_IS_TYPE(o, &mp_type_frozenset)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
STATIC void check_set_or_frozenset(mp_obj_t o) {
|
||||
if (!is_set_or_frozenset(o)) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required"));
|
||||
@@ -72,7 +74,7 @@ STATIC void check_set(mp_obj_t o) {
|
||||
if (!MP_OBJ_IS_TYPE(o, &mp_type_set)) {
|
||||
// Emulate CPython behavior
|
||||
// AttributeError: 'frozenset' object has no attribute 'add'
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"));
|
||||
}
|
||||
@@ -83,11 +85,11 @@ STATIC void check_set(mp_obj_t o) {
|
||||
|
||||
STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_set_t *self = self_in;
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset);
|
||||
#endif
|
||||
if (self->set.used == 0) {
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
if (is_frozen) {
|
||||
print(env, "frozen");
|
||||
}
|
||||
@@ -96,7 +98,7 @@ STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
return;
|
||||
}
|
||||
bool first = true;
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
if (is_frozen) {
|
||||
print(env, "frozenset(");
|
||||
}
|
||||
@@ -112,7 +114,7 @@ STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
}
|
||||
}
|
||||
print(env, "}");
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
if (is_frozen) {
|
||||
print(env, ")");
|
||||
}
|
||||
@@ -158,10 +160,10 @@ const mp_obj_type_t mp_type_set_it = {
|
||||
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set_it));
|
||||
mp_obj_set_it_t *self = self_in;
|
||||
machine_uint_t max = self->set->set.alloc;
|
||||
mp_uint_t max = self->set->set.alloc;
|
||||
mp_set_t *set = &self->set->set;
|
||||
|
||||
for (machine_uint_t i = self->cur; i < max; i++) {
|
||||
for (mp_uint_t i = self->cur; i < max; i++) {
|
||||
if (MP_SET_SLOT_IS_FILLED(set, i)) {
|
||||
self->cur = i + 1;
|
||||
return set->table[i];
|
||||
@@ -474,8 +476,8 @@ STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) {
|
||||
mp_obj_set_t *self = self_in;
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(self->set.used != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->set.used);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((mp_int_t)self->set.used);
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +516,7 @@ STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
return MP_BOOL(elem != NULL);
|
||||
}
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +558,7 @@ const mp_obj_type_t mp_type_set = {
|
||||
.locals_dict = (mp_obj_t)&set_locals_dict,
|
||||
};
|
||||
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
const mp_obj_type_t mp_type_frozenset = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_frozenset,
|
||||
@@ -584,3 +586,5 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {
|
||||
mp_obj_set_t *self = self_in;
|
||||
mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_BUILTINS_SET
|
||||
|
||||
@@ -56,19 +56,26 @@ const mp_obj_ellipsis_t mp_const_ellipsis_obj = {{&mp_type_ellipsis}};
|
||||
/******************************************************************************/
|
||||
/* slice object */
|
||||
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
|
||||
// TODO: This implements only variant of slice with 2 integer args only.
|
||||
// CPython supports 3rd arg (step), plus args can be arbitrary Python objects.
|
||||
typedef struct _mp_obj_slice_t {
|
||||
mp_obj_base_t base;
|
||||
machine_int_t start;
|
||||
machine_int_t stop;
|
||||
mp_obj_t start;
|
||||
mp_obj_t stop;
|
||||
mp_obj_t step;
|
||||
} mp_obj_slice_t;
|
||||
|
||||
void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_slice_t *o = o_in;
|
||||
print(env, "slice(" INT_FMT ", " INT_FMT ")", o->start, o->stop);
|
||||
print(env, "slice(");
|
||||
mp_obj_print_helper(print, env, o->start, PRINT_REPR);
|
||||
print(env, ", ");
|
||||
mp_obj_print_helper(print, env, o->stop, PRINT_REPR);
|
||||
print(env, ", ");
|
||||
mp_obj_print_helper(print, env, o->step, PRINT_REPR);
|
||||
print(env, ")");
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_slice = {
|
||||
@@ -77,39 +84,21 @@ const mp_obj_type_t mp_type_slice = {
|
||||
.print = slice_print,
|
||||
};
|
||||
|
||||
// TODO: Make sure to handle "empty" values, which are signified by None in CPython
|
||||
mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
|
||||
assert(ostep == NULL);
|
||||
machine_int_t start = 0, stop = 0;
|
||||
if (ostart != mp_const_none) {
|
||||
start = mp_obj_get_int(ostart);
|
||||
}
|
||||
if (ostop != mp_const_none) {
|
||||
stop = mp_obj_get_int(ostop);
|
||||
if (stop == 0) {
|
||||
// [x:0] is a special case - in our slice object, stop = 0 means
|
||||
// "end of sequence". Fortunately, [x:0] is an empty seqence for
|
||||
// any x (including negative). [x:x] is also always empty sequence.
|
||||
// but x also can be 0. But note that b""[x:x] is b"" for any x (i.e.
|
||||
// no IndexError, at least in Python 3.3.3). So, we just use -1's to
|
||||
// signify that. -1 is catchy "special" number in case someone will
|
||||
// try to print [x:0] slice ever.
|
||||
start = stop = -1;
|
||||
}
|
||||
}
|
||||
mp_obj_slice_t *o = m_new(mp_obj_slice_t, 1);
|
||||
mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t);
|
||||
o->base.type = &mp_type_slice;
|
||||
o->start = start;
|
||||
o->stop = stop;
|
||||
return (mp_obj_t)o;
|
||||
o->start = ostart;
|
||||
o->stop = ostop;
|
||||
o->step = ostep;
|
||||
return o;
|
||||
}
|
||||
|
||||
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) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice));
|
||||
mp_obj_slice_t *self = self_in;
|
||||
*start = self->start;
|
||||
*stop = self->stop;
|
||||
*step = 1;
|
||||
*step = self->step;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
576
py/objstr.c
576
py/objstr.c
File diff suppressed because it is too large
Load Diff
53
py/objstr.h
53
py/objstr.h
@@ -27,12 +27,61 @@
|
||||
typedef struct _mp_obj_str_t {
|
||||
mp_obj_base_t base;
|
||||
// XXX here we assume the hash size is 16 bits (it is at the moment; see qstr.c)
|
||||
machine_uint_t hash : 16;
|
||||
mp_uint_t hash : 16;
|
||||
// len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte
|
||||
machine_uint_t len : 16;
|
||||
mp_uint_t len : 16;
|
||||
const byte *data;
|
||||
} mp_obj_str_t;
|
||||
|
||||
#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str};
|
||||
|
||||
// use this macro to extract the string hash
|
||||
#define GET_STR_HASH(str_obj_in, str_hash) \
|
||||
uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \
|
||||
{ str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
|
||||
|
||||
// use this macro to extract the string length
|
||||
#define GET_STR_LEN(str_obj_in, str_len) \
|
||||
uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \
|
||||
{ str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; }
|
||||
|
||||
// use this macro to extract the string data and length
|
||||
#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \
|
||||
const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \
|
||||
{ str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \
|
||||
else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; }
|
||||
|
||||
mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len);
|
||||
|
||||
mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
||||
mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
|
||||
mp_obj_t index, bool is_slice);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_encode_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_find_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rfind_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_index_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rindex_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_join_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_split_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rsplit_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_startswith_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_endswith_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_strip_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_lstrip_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rstrip_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_format_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_replace_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_count_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_partition_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_lower_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_upper_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isalpha_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isdigit_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isupper_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_islower_obj);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -34,24 +35,25 @@
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "stream.h"
|
||||
#include "objstr.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_IO
|
||||
#if MICROPY_PY_IO
|
||||
|
||||
typedef struct _mp_obj_stringio_t {
|
||||
mp_obj_base_t base;
|
||||
vstr_t *vstr;
|
||||
// StringIO has single pointer used for both reading and writing
|
||||
machine_uint_t pos;
|
||||
mp_uint_t pos;
|
||||
} mp_obj_stringio_t;
|
||||
|
||||
STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_stringio_t *self = self_in;
|
||||
print(env, "<io.StringIO 0x%x>", self->vstr);
|
||||
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
|
||||
}
|
||||
|
||||
STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) {
|
||||
STATIC mp_int_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_stringio_t *o = o_in;
|
||||
machine_uint_t remaining = o->vstr->len - o->pos;
|
||||
mp_uint_t remaining = o->vstr->len - o->pos;
|
||||
if (size > remaining) {
|
||||
size = remaining;
|
||||
}
|
||||
@@ -60,9 +62,9 @@ STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) {
|
||||
STATIC mp_int_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_stringio_t *o = o_in;
|
||||
machine_uint_t remaining = o->vstr->alloc - o->pos;
|
||||
mp_uint_t remaining = o->vstr->alloc - o->pos;
|
||||
if (size > remaining) {
|
||||
// Take all what's already allocated...
|
||||
o->vstr->len = o->vstr->alloc;
|
||||
@@ -77,9 +79,11 @@ STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint
|
||||
return size;
|
||||
}
|
||||
|
||||
#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)
|
||||
|
||||
STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
|
||||
mp_obj_stringio_t *self = self_in;
|
||||
return mp_obj_new_str((byte*)self->vstr->buf, self->vstr->len, false);
|
||||
return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
|
||||
|
||||
@@ -96,16 +100,16 @@ mp_obj_t stringio___exit__(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
|
||||
|
||||
STATIC mp_obj_stringio_t *stringio_new() {
|
||||
STATIC mp_obj_stringio_t *stringio_new(mp_obj_t type_in) {
|
||||
mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
|
||||
o->base.type = &mp_type_stringio;
|
||||
o->base.type = type_in;
|
||||
o->vstr = vstr_new();
|
||||
o->pos = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t stringio_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_stringio_t *o = stringio_new();
|
||||
mp_obj_stringio_t *o = stringio_new(type_in);
|
||||
|
||||
if (n_args > 0) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
@@ -135,6 +139,12 @@ STATIC const mp_stream_p_t stringio_stream_p = {
|
||||
.write = stringio_write,
|
||||
};
|
||||
|
||||
STATIC const mp_stream_p_t bytesio_stream_p = {
|
||||
.read = stringio_read,
|
||||
.write = stringio_write,
|
||||
.is_bytes = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_stringio = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_StringIO,
|
||||
@@ -146,4 +156,17 @@ const mp_obj_type_t mp_type_stringio = {
|
||||
.locals_dict = (mp_obj_t)&stringio_locals_dict,
|
||||
};
|
||||
|
||||
#if MICROPY_PY_IO_BYTESIO
|
||||
const mp_obj_type_t mp_type_bytesio = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_BytesIO,
|
||||
.print = stringio_print,
|
||||
.make_new = stringio_make_new,
|
||||
.getiter = mp_identity,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.stream_p = &bytesio_stream_p,
|
||||
.locals_dict = (mp_obj_t)&stringio_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
359
py/objstrunicode.c
Normal file
359
py/objstrunicode.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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 "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "pfenv.h"
|
||||
#include "objstr.h"
|
||||
#include "objlist.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
|
||||
|
||||
/******************************************************************************/
|
||||
/* str */
|
||||
|
||||
STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
|
||||
// this escapes characters, but it will be very slow to print (calling print many times)
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
|
||||
if (*s == '\'') {
|
||||
has_single_quote = true;
|
||||
} else if (*s == '"') {
|
||||
has_double_quote = true;
|
||||
}
|
||||
}
|
||||
int quote_char = '\'';
|
||||
if (has_single_quote && !has_double_quote) {
|
||||
quote_char = '"';
|
||||
}
|
||||
print(env, "%c", quote_char);
|
||||
const byte *s = str_data, *top = str_data + str_len;
|
||||
while (s < top) {
|
||||
unichar ch;
|
||||
ch = utf8_get_char(s);
|
||||
s = utf8_next_char(s);
|
||||
if (ch == quote_char) {
|
||||
print(env, "\\%c", quote_char);
|
||||
} else if (ch == '\\') {
|
||||
print(env, "\\\\");
|
||||
} else if (32 <= ch && ch <= 126) {
|
||||
print(env, "%c", ch);
|
||||
} else if (ch == '\n') {
|
||||
print(env, "\\n");
|
||||
} else if (ch == '\r') {
|
||||
print(env, "\\r");
|
||||
} else if (ch == '\t') {
|
||||
print(env, "\\t");
|
||||
} else if (ch < 0x100) {
|
||||
print(env, "\\x%02x", ch);
|
||||
} else if (ch < 0x10000) {
|
||||
print(env, "\\u%04x", ch);
|
||||
} else {
|
||||
print(env, "\\U%08x", ch);
|
||||
}
|
||||
}
|
||||
print(env, "%c", quote_char);
|
||||
}
|
||||
|
||||
STATIC void uni_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
if (kind == PRINT_STR) {
|
||||
print(env, "%.*s", str_len, str_data);
|
||||
} else {
|
||||
uni_print_quoted(print, env, str_data, str_len);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uni_unary_op(int op, mp_obj_t self_in) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL:
|
||||
return MP_BOOL(str_len != 0);
|
||||
case MP_UNARY_OP_LEN:
|
||||
return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len));
|
||||
default:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (n_kw != 0) {
|
||||
mp_arg_error_unimpl_kw();
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
return MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
|
||||
case 1:
|
||||
{
|
||||
vstr_t *vstr = vstr_new();
|
||||
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR);
|
||||
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
// TODO: validate 2nd/3rd args
|
||||
if (!MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected"));
|
||||
}
|
||||
GET_STR_DATA_LEN(args[0], str_data, str_len);
|
||||
GET_STR_HASH(args[0], str_hash);
|
||||
mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_str, NULL, str_len);
|
||||
o->data = str_data;
|
||||
o->hash = str_hash;
|
||||
return o;
|
||||
}
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments"));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or
|
||||
// be capped to the first/last character of the string, depending on is_slice.
|
||||
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
|
||||
mp_obj_t index, bool is_slice) {
|
||||
mp_int_t i;
|
||||
// Copied from mp_get_index; I don't want bounds checking, just give me
|
||||
// the integer as-is. (I can't bounds-check without scanning the whole
|
||||
// string; an out-of-bounds index will be caught in the loops below.)
|
||||
if (MP_OBJ_IS_SMALL_INT(index)) {
|
||||
i = MP_OBJ_SMALL_INT_VALUE(index);
|
||||
} else if (!mp_obj_get_int_maybe(index, &i)) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index)));
|
||||
}
|
||||
const byte *s, *top = self_data + self_len;
|
||||
if (i < 0)
|
||||
{
|
||||
// Negative indexing is performed by counting from the end of the string.
|
||||
for (s = top - 1; i; --s) {
|
||||
if (s < self_data) {
|
||||
if (is_slice) {
|
||||
return self_data;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range"));
|
||||
}
|
||||
if (!UTF8_IS_CONT(*s)) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
++s;
|
||||
} else if (!i) {
|
||||
return self_data; // Shortcut - str[0] is its base pointer
|
||||
} else {
|
||||
// Positive indexing, correspondingly, counts from the start of the string.
|
||||
// It's assumed that negative indexing will generally be used with small
|
||||
// absolute values (eg str[-1], not str[-1000000]), which means it'll be
|
||||
// more efficient this way.
|
||||
for (s = self_data; true; ++s) {
|
||||
if (s >= top) {
|
||||
if (is_slice) {
|
||||
return top;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range"));
|
||||
}
|
||||
while (UTF8_IS_CONT(*s)) {
|
||||
++s;
|
||||
}
|
||||
if (!i--) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(self_in);
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
mp_obj_t ostart, ostop, ostep;
|
||||
mp_obj_slice_get(index, &ostart, &ostop, &ostep);
|
||||
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
"only slices with step=1 (aka None) are supported"));
|
||||
}
|
||||
|
||||
if (type == &mp_type_bytes) {
|
||||
mp_int_t start = 0, stop = self_len;
|
||||
if (ostart != mp_const_none) {
|
||||
start = MP_OBJ_SMALL_INT_VALUE(ostart);
|
||||
if (start < 0) {
|
||||
start = self_len + start;
|
||||
}
|
||||
}
|
||||
if (ostop != mp_const_none) {
|
||||
stop = MP_OBJ_SMALL_INT_VALUE(ostop);
|
||||
if (stop < 0) {
|
||||
stop = self_len + stop;
|
||||
}
|
||||
}
|
||||
return mp_obj_new_str_of_type(type, self_data + start, stop - start);
|
||||
}
|
||||
const byte *pstart, *pstop;
|
||||
if (ostart != mp_const_none) {
|
||||
pstart = str_index_to_ptr(type, self_data, self_len, ostart, true);
|
||||
} else {
|
||||
pstart = self_data;
|
||||
}
|
||||
if (ostop != mp_const_none) {
|
||||
// pstop will point just after the stop character. This depends on
|
||||
// the \0 at the end of the string.
|
||||
pstop = str_index_to_ptr(type, self_data, self_len, ostop, true);
|
||||
} else {
|
||||
pstop = self_data + self_len;
|
||||
}
|
||||
if (pstop < pstart) {
|
||||
return MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
}
|
||||
return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart);
|
||||
}
|
||||
#endif
|
||||
if (type == &mp_type_bytes) {
|
||||
uint index_val = mp_get_index(type, self_len, index, false);
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_int_t)self_data[index_val]);
|
||||
}
|
||||
const byte *s = str_index_to_ptr(type, self_data, self_len, index, false);
|
||||
int len = 1;
|
||||
if (UTF8_IS_NONASCII(*s)) {
|
||||
// Count the number of 1 bits (after the first)
|
||||
for (char mask = 0x40; *s & mask; mask >>= 1) {
|
||||
++len;
|
||||
}
|
||||
}
|
||||
return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string
|
||||
} else {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&str_index_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rindex), (mp_obj_t)&str_rindex_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_join), (mp_obj_t)&str_join_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t)&str_split_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rsplit), (mp_obj_t)&str_rsplit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_startswith), (mp_obj_t)&str_startswith_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_endswith), (mp_obj_t)&str_endswith_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_strip), (mp_obj_t)&str_strip_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_lstrip), (mp_obj_t)&str_lstrip_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rstrip), (mp_obj_t)&str_rstrip_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&str_format_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_replace), (mp_obj_t)&str_replace_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&str_count_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_partition), (mp_obj_t)&str_partition_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t mp_type_str = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_str,
|
||||
.print = uni_print,
|
||||
.make_new = str_make_new,
|
||||
.unary_op = uni_unary_op,
|
||||
.binary_op = mp_obj_str_binary_op,
|
||||
.subscr = str_subscr,
|
||||
.getiter = mp_obj_new_str_iterator,
|
||||
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&str_locals_dict,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/* str iterator */
|
||||
|
||||
typedef struct _mp_obj_str_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t str;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_str_it_t;
|
||||
|
||||
STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
|
||||
mp_obj_str_it_t *self = self_in;
|
||||
GET_STR_DATA_LEN(self->str, str, len);
|
||||
if (self->cur < len) {
|
||||
const byte *cur = str + self->cur;
|
||||
const byte *end = utf8_next_char(str + self->cur);
|
||||
mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true);
|
||||
self->cur += end - cur;
|
||||
return o_out;
|
||||
} else {
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_str_it = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_iterator,
|
||||
.getiter = mp_identity,
|
||||
.iternext = str_it_iternext,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
|
||||
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
|
||||
o->base.type = &mp_type_str_it;
|
||||
o->str = str;
|
||||
o->cur = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
@@ -120,7 +120,7 @@ mp_obj_t mp_obj_tuple_unary_op(int op, mp_obj_t self_in) {
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(self->len != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
|
||||
default: return MP_OBJ_NOT_SUPPORTED;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_ADD: {
|
||||
if (!mp_obj_is_subclass_fast(mp_obj_get_type(rhs), (mp_obj_t)&mp_type_tuple)) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
mp_obj_tuple_t *p = rhs;
|
||||
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len + p->len, NULL);
|
||||
@@ -138,7 +138,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
}
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
if (!MP_OBJ_IS_SMALL_INT(rhs)) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
int n = MP_OBJ_SMALL_INT_VALUE(rhs);
|
||||
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL);
|
||||
@@ -153,8 +153,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
return MP_BOOL(tuple_cmp_helper(op, lhs, rhs));
|
||||
|
||||
default:
|
||||
// op not supported
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,21 +161,22 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
mp_obj_tuple_t *self = self_in;
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
machine_uint_t start, stop;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
|
||||
assert(0);
|
||||
mp_bound_slice_t slice;
|
||||
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
"only slices with step=1 (aka None) are supported"));
|
||||
}
|
||||
mp_obj_tuple_t *res = mp_obj_new_tuple(stop - start, NULL);
|
||||
mp_seq_copy(res->items, self->items + start, res->len, mp_obj_t);
|
||||
mp_obj_tuple_t *res = mp_obj_new_tuple(slice.stop - slice.start, NULL);
|
||||
mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
uint index_value = mp_get_index(self->base.type, self->len, index, false);
|
||||
return self->items[index_value];
|
||||
} else {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,11 +252,11 @@ void mp_obj_tuple_del(mp_obj_t self_in) {
|
||||
m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self);
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
|
||||
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple));
|
||||
mp_obj_tuple_t *self = self_in;
|
||||
// start hash with pointer to empty tuple, to make it fairly unique
|
||||
machine_int_t hash = (machine_int_t)mp_const_empty_tuple;
|
||||
mp_int_t hash = (mp_int_t)mp_const_empty_tuple;
|
||||
for (uint i = 0; i < self->len; i++) {
|
||||
hash += mp_obj_hash(self->items[i]);
|
||||
}
|
||||
@@ -269,7 +269,7 @@ machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
|
||||
typedef struct _mp_obj_tuple_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_tuple_t *tuple;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_tuple_it_t;
|
||||
|
||||
STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
typedef struct _mp_obj_tuple_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t len;
|
||||
mp_uint_t len;
|
||||
mp_obj_t items[];
|
||||
} mp_obj_tuple_t;
|
||||
|
||||
|
||||
316
py/objtype.c
316
py/objtype.c
@@ -4,6 +4,7 @@
|
||||
* 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
|
||||
@@ -45,11 +46,15 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t static_class_method_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
|
||||
/******************************************************************************/
|
||||
// instance object
|
||||
|
||||
#define is_instance_type(type) ((type)->make_new == instance_make_new)
|
||||
#define is_native_type(type) ((type)->make_new != instance_make_new)
|
||||
STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) {
|
||||
mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs);
|
||||
@@ -95,18 +100,26 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
|
||||
// it was - because instance->subobj[0] is of that type. The only exception is when
|
||||
// object is not yet constructed, then we need to know base native type to construct
|
||||
// instance->subobj[0]. This case is handled via instance_count_native_bases() though.
|
||||
STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type, qstr attr, machine_uint_t meth_offset, mp_obj_t *dest) {
|
||||
assert(dest[0] == NULL);
|
||||
assert(dest[1] == NULL);
|
||||
struct class_lookup_data {
|
||||
mp_obj_instance_t *obj;
|
||||
qstr attr;
|
||||
mp_uint_t meth_offset;
|
||||
mp_obj_t *dest;
|
||||
bool is_type;
|
||||
};
|
||||
|
||||
STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {
|
||||
assert(lookup->dest[0] == NULL);
|
||||
assert(lookup->dest[1] == NULL);
|
||||
for (;;) {
|
||||
// Optimize special method lookup for native types
|
||||
// This avoids extra method_name => slot lookup. On the other hand,
|
||||
// this should not be applied to class types, as will result in extra
|
||||
// lookup either.
|
||||
if (meth_offset != 0 && is_native_type(type)) {
|
||||
if (*(void**)((char*)type + meth_offset) != NULL) {
|
||||
DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(attr));
|
||||
dest[0] = MP_OBJ_SENTINEL;
|
||||
if (lookup->meth_offset != 0 && is_native_type(type)) {
|
||||
if (*(void**)((char*)type + lookup->meth_offset) != NULL) {
|
||||
DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(lookup->attr));
|
||||
lookup->dest[0] = MP_OBJ_SENTINEL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -115,23 +128,33 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
|
||||
// search locals_dict (the set of methods/attributes)
|
||||
assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
|
||||
mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
|
||||
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
dest[0] = elem->value;
|
||||
if (o != MP_OBJ_NULL && is_native_type(type)) {
|
||||
dest[1] = o->subobj[0];
|
||||
lookup->dest[0] = elem->value;
|
||||
if (lookup->is_type) {
|
||||
// If we look up class method, we need to pass original type there,
|
||||
// not type where we found a class method.
|
||||
const mp_obj_type_t *org_type = (const mp_obj_type_t*)lookup->obj;
|
||||
instance_convert_return_attr(NULL, org_type, elem->value, lookup->dest);
|
||||
} else if (lookup->obj != MP_OBJ_NULL && !lookup->is_type && is_native_type(type)) {
|
||||
instance_convert_return_attr(lookup->obj->subobj[0], type, elem->value, lookup->dest);
|
||||
} else {
|
||||
instance_convert_return_attr(lookup->obj, type, elem->value, lookup->dest);
|
||||
}
|
||||
// TODO: Sensibly, we should call instance_convert_return_attr() here,
|
||||
// instead of multiple places later. Also, this code duplicates runtime.c much.
|
||||
#if DEBUG_PRINT
|
||||
printf("mp_obj_class_lookup: Returning: ");
|
||||
mp_obj_print(lookup->dest[0], PRINT_REPR); printf(" ");
|
||||
mp_obj_print(lookup->dest[1], PRINT_REPR); printf("\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try this for completeness, but all native methods should be statically defined
|
||||
// in locals_dict, and would be handled by above.
|
||||
if (o != MP_OBJ_NULL && is_native_type(type)) {
|
||||
mp_load_method_maybe(o->subobj[0], attr, dest);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
if (lookup->obj != MP_OBJ_NULL && !lookup->is_type && is_native_type(type)) {
|
||||
mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest);
|
||||
if (lookup->dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -156,8 +179,8 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
|
||||
// Not a "real" type
|
||||
continue;
|
||||
}
|
||||
mp_obj_class_lookup(o, bt, attr, meth_offset, dest);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
mp_obj_class_lookup(lookup, bt);
|
||||
if (lookup->dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -176,10 +199,18 @@ STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void
|
||||
mp_obj_instance_t *self = self_in;
|
||||
qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(self, self->base.type, meth, offsetof(mp_obj_type_t, print), member);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.attr = meth,
|
||||
.meth_offset = offsetof(mp_obj_type_t, print),
|
||||
.dest = member,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {
|
||||
// If there's no __str__, fall back to __repr__
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___repr__, 0, member);
|
||||
lookup.attr = MP_QSTR___repr__;
|
||||
lookup.meth_offset = 0;
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
}
|
||||
|
||||
if (member[0] == MP_OBJ_SENTINEL) {
|
||||
@@ -205,7 +236,7 @@ STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void
|
||||
print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_t instance_make_new(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_type));
|
||||
mp_obj_type_t *self = self_in;
|
||||
|
||||
@@ -215,38 +246,73 @@ STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, cons
|
||||
|
||||
mp_obj_instance_t *o = mp_obj_new_instance(self_in, num_native_bases);
|
||||
|
||||
// look for __init__ function
|
||||
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(NULL, self, MP_QSTR___init__, offsetof(mp_obj_type_t, make_new), init_fn);
|
||||
// This executes only "__new__" part of obejection creation.
|
||||
// TODO: This won't work will for classes with native bases.
|
||||
// TODO: This is hack, should be resolved along the lines of
|
||||
// https://github.com/micropython/micropython/issues/606#issuecomment-43685883
|
||||
if (n_args == 1 && *args == MP_OBJ_SENTINEL) {
|
||||
return o;
|
||||
}
|
||||
|
||||
// look for __new__ function
|
||||
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = NULL,
|
||||
.attr = MP_QSTR___new__,
|
||||
.meth_offset = offsetof(mp_obj_type_t, make_new),
|
||||
.dest = init_fn,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self);
|
||||
|
||||
mp_obj_t new_ret = o;
|
||||
if (init_fn[0] == MP_OBJ_SENTINEL) {
|
||||
// Native type's constructor is what wins - it gets all our arguments,
|
||||
// and none Python classes are initialized at all.
|
||||
o->subobj[0] = native_base->make_new((mp_obj_type_t*)native_base, n_args, n_kw, args);
|
||||
} else if (init_fn[0] != MP_OBJ_NULL) {
|
||||
// We need to default-initialize any native subobjs first
|
||||
if (num_native_bases > 0) {
|
||||
o->subobj[0] = native_base->make_new((mp_obj_type_t*)native_base, 0, 0, NULL);
|
||||
}
|
||||
// now call Python class __init__ function with all args
|
||||
mp_obj_t init_ret;
|
||||
// now call Python class __new__ function with all args
|
||||
if (n_args == 0 && n_kw == 0) {
|
||||
init_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&o);
|
||||
new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&self_in);
|
||||
} else {
|
||||
mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);
|
||||
args2[0] = o;
|
||||
args2[0] = self_in;
|
||||
memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
|
||||
init_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
|
||||
new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
|
||||
m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// https://docs.python.org/3.4/reference/datamodel.html#object.__new__
|
||||
// "If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked."
|
||||
if (mp_obj_get_type(new_ret) != self_in) {
|
||||
return new_ret;
|
||||
}
|
||||
|
||||
o = new_ret;
|
||||
|
||||
// now call Python class __init__ function with all args
|
||||
init_fn[0] = init_fn[1] = NULL;
|
||||
lookup.obj = o;
|
||||
lookup.attr = MP_QSTR___init__;
|
||||
lookup.meth_offset = 0;
|
||||
mp_obj_class_lookup(&lookup, self);
|
||||
if (init_fn[0] != MP_OBJ_NULL) {
|
||||
mp_obj_t init_ret;
|
||||
if (n_args == 0 && n_kw == 0) {
|
||||
init_ret = mp_call_method_n_kw(0, 0, init_fn);
|
||||
} else {
|
||||
mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw);
|
||||
args2[0] = init_fn[0];
|
||||
args2[1] = init_fn[1];
|
||||
memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
|
||||
init_ret = mp_call_method_n_kw(n_args, n_kw, args2);
|
||||
m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
|
||||
}
|
||||
if (init_ret != mp_const_none) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret)));
|
||||
}
|
||||
|
||||
} else {
|
||||
if (n_args != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object() takes no parameters"));
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
@@ -266,17 +332,23 @@ STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) {
|
||||
qstr op_name = unary_op_method_name[op];
|
||||
/* Still try to lookup native slot
|
||||
if (op_name == 0) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
*/
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(self, self->base.type, op_name, offsetof(mp_obj_type_t, unary_op), member);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.attr = op_name,
|
||||
.meth_offset = offsetof(mp_obj_type_t, unary_op),
|
||||
.dest = member,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
if (member[0] == MP_OBJ_SENTINEL) {
|
||||
return mp_unary_op(op, self->subobj[0]);
|
||||
} else if (member[0] != MP_OBJ_NULL) {
|
||||
return mp_call_function_1(member[0], self_in);
|
||||
} else {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,14 +379,16 @@ STATIC const qstr binary_op_method_name[] = {
|
||||
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
|
||||
MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
|
||||
MP_BINARY_OP_INPLACE_MODULO,
|
||||
MP_BINARY_OP_INPLACE_POWER,
|
||||
MP_BINARY_OP_LESS,
|
||||
MP_BINARY_OP_MORE,
|
||||
MP_BINARY_OP_INPLACE_POWER,*/
|
||||
[MP_BINARY_OP_LESS] = MP_QSTR___lt__,
|
||||
/*MP_BINARY_OP_MORE,
|
||||
MP_BINARY_OP_EQUAL,
|
||||
MP_BINARY_OP_LESS_EQUAL,
|
||||
MP_BINARY_OP_MORE_EQUAL,
|
||||
MP_BINARY_OP_NOT_EQUAL,
|
||||
MP_BINARY_OP_IN,
|
||||
*/
|
||||
[MP_BINARY_OP_IN] = MP_QSTR___contains__,
|
||||
/*
|
||||
MP_BINARY_OP_IS,
|
||||
*/
|
||||
[MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size
|
||||
@@ -323,8 +397,8 @@ STATIC const qstr binary_op_method_name[] = {
|
||||
// Given a member that was extracted from an instance, convert it correctly
|
||||
// and put the result in the dest[] array for a possible method call.
|
||||
// Conversion means dealing with static/class methods, callables, and values.
|
||||
// see http://docs.python.org/3.3/howto/descriptor.html
|
||||
STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_t *dest) {
|
||||
// see http://docs.python.org/3/howto/descriptor.html
|
||||
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) {
|
||||
assert(dest[1] == NULL);
|
||||
if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) {
|
||||
// return just the function
|
||||
@@ -332,7 +406,7 @@ STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_
|
||||
} else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) {
|
||||
// return a bound method, with self being the type of this object
|
||||
dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
|
||||
dest[1] = mp_obj_get_type(self);
|
||||
dest[1] = (mp_obj_t)type;
|
||||
} else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) {
|
||||
// Don't try to bind types
|
||||
dest[0] = member;
|
||||
@@ -353,26 +427,30 @@ STATIC mp_obj_t instance_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
qstr op_name = binary_op_method_name[op];
|
||||
/* Still try to lookup native slot
|
||||
if (op_name == 0) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
*/
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(lhs, lhs->base.type, op_name, offsetof(mp_obj_type_t, binary_op), member);
|
||||
if (member[0] == MP_OBJ_SENTINEL) {
|
||||
mp_obj_t dest[3] = {MP_OBJ_NULL};
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = lhs,
|
||||
.attr = op_name,
|
||||
.meth_offset = offsetof(mp_obj_type_t, binary_op),
|
||||
.dest = dest,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, lhs->base.type);
|
||||
if (dest[0] == MP_OBJ_SENTINEL) {
|
||||
return mp_binary_op(op, lhs->subobj[0], rhs_in);
|
||||
} else if (member[0] != MP_OBJ_NULL) {
|
||||
mp_obj_t dest[3];
|
||||
dest[1] = MP_OBJ_NULL;
|
||||
instance_convert_return_attr(lhs_in, member[0], dest);
|
||||
} else if (dest[0] != MP_OBJ_NULL) {
|
||||
dest[2] = rhs_in;
|
||||
return mp_call_method_n_kw(1, 0, dest);
|
||||
} else {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
// logic: look in obj members then class locals (TODO check this against CPython)
|
||||
assert(is_instance_type(mp_obj_get_type(self_in)));
|
||||
mp_obj_instance_t *self = self_in;
|
||||
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||
@@ -383,12 +461,17 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp_obj_class_lookup(self, self->base.type, attr, 0, dest);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.attr = attr,
|
||||
.meth_offset = 0,
|
||||
.dest = dest,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
mp_obj_t member = dest[0];
|
||||
if (member != MP_OBJ_NULL) {
|
||||
if (0) {
|
||||
#if MICROPY_ENABLE_PROPERTY
|
||||
} else if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
|
||||
// object member is a property
|
||||
// delegate the store to the property
|
||||
// TODO should this be part of instance_convert_return_attr?
|
||||
@@ -399,15 +482,8 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
|
||||
// TODO should we convert the returned value using instance_convert_return_attr?
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// not a property
|
||||
// if we don't yet have bound method (supposedly from native base), go
|
||||
// try to convert own attrs.
|
||||
if (dest[1] == MP_OBJ_NULL) {
|
||||
instance_convert_return_attr(self_in, member, dest);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -428,11 +504,17 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
|
||||
mp_obj_instance_t *self = self_in;
|
||||
|
||||
#if MICROPY_ENABLE_PROPERTY
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
// for property, we need to do a lookup first in the class dict
|
||||
// this makes all stores slow... how to fix?
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(self, self->base.type, attr, 0, member);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.attr = attr,
|
||||
.meth_offset = 0,
|
||||
.dest = member,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
if (member[0] != MP_OBJ_NULL && MP_OBJ_IS_TYPE(member[0], &mp_type_property)) {
|
||||
// attribute already exists and is a property
|
||||
// delegate the store to the property
|
||||
@@ -462,18 +544,26 @@ STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
|
||||
STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
mp_obj_instance_t *self = self_in;
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.meth_offset = offsetof(mp_obj_type_t, subscr),
|
||||
.dest = member,
|
||||
};
|
||||
uint meth_args;
|
||||
if (value == MP_OBJ_NULL) {
|
||||
// delete item
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___delitem__, offsetof(mp_obj_type_t, subscr), member);
|
||||
lookup.attr = MP_QSTR___delitem__;
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
meth_args = 2;
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
// load item
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, offsetof(mp_obj_type_t, subscr), member);
|
||||
lookup.attr = MP_QSTR___getitem__;
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
meth_args = 2;
|
||||
} else {
|
||||
// store item
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___setitem__, offsetof(mp_obj_type_t, subscr), member);
|
||||
lookup.attr = MP_QSTR___setitem__;
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
meth_args = 3;
|
||||
}
|
||||
if (member[0] == MP_OBJ_SENTINEL) {
|
||||
@@ -488,16 +578,22 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
|
||||
return mp_const_none;
|
||||
}
|
||||
} else {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_instance_t *self = self_in;
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___call__, offsetof(mp_obj_type_t, call), member);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.attr = MP_QSTR___call__,
|
||||
.meth_offset = offsetof(mp_obj_type_t, call),
|
||||
.dest = member,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
if (member[0] == MP_OBJ_NULL) {
|
||||
return MP_OBJ_NULL;
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in)));
|
||||
}
|
||||
if (member[0] == MP_OBJ_SENTINEL) {
|
||||
return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
|
||||
@@ -509,13 +605,20 @@ STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp
|
||||
STATIC mp_obj_t instance_getiter(mp_obj_t self_in) {
|
||||
mp_obj_instance_t *self = self_in;
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___iter__, offsetof(mp_obj_type_t, getiter), member);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self,
|
||||
.attr = MP_QSTR___iter__,
|
||||
.meth_offset = offsetof(mp_obj_type_t, getiter),
|
||||
.dest = member,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
if (member[0] == MP_OBJ_NULL) {
|
||||
// This kinda duplicates code in mp_getiter()
|
||||
mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, 0, member);
|
||||
lookup.attr = MP_QSTR___getitem__;
|
||||
lookup.meth_offset = 0; // TODO
|
||||
mp_obj_class_lookup(&lookup, self->base.type);
|
||||
if (member[0] != MP_OBJ_NULL) {
|
||||
// __getitem__ exists, create an iterator
|
||||
instance_convert_return_attr(self_in, member[0], member);
|
||||
return mp_obj_new_getitem_iter(member);
|
||||
}
|
||||
return MP_OBJ_NULL;
|
||||
@@ -583,24 +686,14 @@ STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(NULL, self, attr, 0, member);
|
||||
if (member[0] != MP_OBJ_NULL) {
|
||||
// check if the methods are functions, static or class methods
|
||||
// see http://docs.python.org/3.3/howto/descriptor.html
|
||||
if (MP_OBJ_IS_TYPE(member[0], &mp_type_staticmethod)) {
|
||||
// return just the function
|
||||
dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun;
|
||||
} else if (MP_OBJ_IS_TYPE(member[0], &mp_type_classmethod)) {
|
||||
// return a bound method, with self being this class
|
||||
dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun;
|
||||
dest[1] = self_in;
|
||||
} else {
|
||||
// return just the function
|
||||
// TODO need to wrap in a type check for the first argument; eg list.append(1,1) needs to throw an exception
|
||||
dest[0] = member[0];
|
||||
}
|
||||
}
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self_in,
|
||||
.attr = attr,
|
||||
.meth_offset = 0,
|
||||
.dest = dest,
|
||||
.is_type = true,
|
||||
};
|
||||
mp_obj_class_lookup(&lookup, self);
|
||||
}
|
||||
|
||||
STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
|
||||
@@ -639,7 +732,7 @@ STATIC mp_obj_t type_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return MP_BOOL(lhs_in == rhs_in);
|
||||
|
||||
default:
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,6 +751,8 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // Micro Python restriction, for now
|
||||
assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // Micro Python restriction, for now
|
||||
|
||||
// TODO might need to make a copy of locals_dict; at least that's how CPython does it
|
||||
|
||||
// Basic validation of base classes
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
@@ -692,6 +787,16 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"));
|
||||
}
|
||||
|
||||
mp_map_t *locals_map = mp_obj_dict_get_map(o->locals_dict);
|
||||
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
// __new__ slot exists; check if it is a function
|
||||
if (MP_OBJ_IS_TYPE(elem->value, &mp_type_fun_native) || MP_OBJ_IS_TYPE(elem->value, &mp_type_fun_bc)) {
|
||||
// __new__ is a function, wrap it in a staticmethod decorator
|
||||
elem->value = static_class_method_make_new((mp_obj_t)&mp_type_staticmethod, 1, 0, &elem->value);
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -739,15 +844,20 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_tuple_get(type->bases_tuple, &len, &items);
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = self->obj,
|
||||
.attr = attr,
|
||||
.meth_offset = 0,
|
||||
.dest = dest,
|
||||
};
|
||||
for (uint i = 0; i < len; i++) {
|
||||
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
|
||||
mp_obj_t member[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, member);
|
||||
if (member[0] != MP_OBJ_NULL) {
|
||||
instance_convert_return_attr(self->obj, member[0], dest);
|
||||
mp_obj_class_lookup(&lookup, (mp_obj_type_t*)items[i]);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mp_obj_class_lookup(&lookup, &mp_type_object);
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_super = {
|
||||
|
||||
176
py/parse.c
176
py/parse.c
@@ -28,13 +28,15 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parsenumbase.h"
|
||||
#include "parse.h"
|
||||
#include "smallint.h"
|
||||
|
||||
#define RULE_ACT_KIND_MASK (0xf0)
|
||||
#define RULE_ACT_ARG_MASK (0x0f)
|
||||
@@ -70,6 +72,7 @@ enum {
|
||||
#include "grammar.h"
|
||||
#undef DEF_RULE
|
||||
RULE_maximum_number_of,
|
||||
RULE_string, // special node for non-interned string
|
||||
};
|
||||
|
||||
#define or(n) (RULE_ACT_OR | n)
|
||||
@@ -106,20 +109,20 @@ STATIC const rule_t *rules[] = {
|
||||
};
|
||||
|
||||
typedef struct _rule_stack_t {
|
||||
unsigned int src_line : 24;
|
||||
unsigned int rule_id : 8;
|
||||
int32_t arg_i; // what should be the size and signedness?
|
||||
mp_uint_t src_line : 24;
|
||||
mp_uint_t rule_id : 8;
|
||||
mp_uint_t arg_i : 32; // what should the bit-size be?
|
||||
} rule_stack_t;
|
||||
|
||||
typedef struct _parser_t {
|
||||
bool had_memory_error;
|
||||
|
||||
uint rule_stack_alloc;
|
||||
uint rule_stack_top;
|
||||
mp_uint_t rule_stack_alloc;
|
||||
mp_uint_t rule_stack_top;
|
||||
rule_stack_t *rule_stack;
|
||||
|
||||
uint result_stack_alloc;
|
||||
uint result_stack_top;
|
||||
mp_uint_t result_stack_alloc;
|
||||
mp_uint_t result_stack_top;
|
||||
mp_parse_node_t *result_stack;
|
||||
|
||||
mp_lexer_t *lexer;
|
||||
@@ -129,18 +132,18 @@ STATIC inline void memory_error(parser_t *parser) {
|
||||
parser->had_memory_error = true;
|
||||
}
|
||||
|
||||
STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int arg_i) {
|
||||
STATIC void push_rule(parser_t *parser, mp_uint_t src_line, const rule_t *rule, mp_uint_t arg_i) {
|
||||
if (parser->had_memory_error) {
|
||||
return;
|
||||
}
|
||||
if (parser->rule_stack_top >= parser->rule_stack_alloc) {
|
||||
rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MP_ALLOC_PARSE_RULE_INC);
|
||||
rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC);
|
||||
if (rs == NULL) {
|
||||
memory_error(parser);
|
||||
return;
|
||||
}
|
||||
parser->rule_stack = rs;
|
||||
parser->rule_stack_alloc += MP_ALLOC_PARSE_RULE_INC;
|
||||
parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC;
|
||||
}
|
||||
rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];
|
||||
rs->src_line = src_line;
|
||||
@@ -148,14 +151,14 @@ STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int ar
|
||||
rs->arg_i = arg_i;
|
||||
}
|
||||
|
||||
STATIC void push_rule_from_arg(parser_t *parser, uint arg) {
|
||||
STATIC void push_rule_from_arg(parser_t *parser, mp_uint_t arg) {
|
||||
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
|
||||
uint rule_id = arg & RULE_ARG_ARG_MASK;
|
||||
mp_uint_t rule_id = arg & RULE_ARG_ARG_MASK;
|
||||
assert(rule_id < RULE_maximum_number_of);
|
||||
push_rule(parser, mp_lexer_cur(parser->lexer)->src_line, rules[rule_id], 0);
|
||||
}
|
||||
|
||||
STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *src_line) {
|
||||
STATIC void pop_rule(parser_t *parser, const rule_t **rule, mp_uint_t *arg_i, mp_uint_t *src_line) {
|
||||
assert(!parser->had_memory_error);
|
||||
parser->rule_stack_top -= 1;
|
||||
*rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id];
|
||||
@@ -163,52 +166,52 @@ STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *s
|
||||
*src_line = parser->rule_stack[parser->rule_stack_top].src_line;
|
||||
}
|
||||
|
||||
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
|
||||
mp_parse_node_t mp_parse_node_new_leaf(mp_int_t kind, mp_int_t arg) {
|
||||
if (kind == MP_PARSE_NODE_SMALL_INT) {
|
||||
return (mp_parse_node_t)(kind | (arg << 1));
|
||||
}
|
||||
return (mp_parse_node_t)(kind | (arg << 5));
|
||||
}
|
||||
|
||||
uint mp_parse_node_free(mp_parse_node_t pn) {
|
||||
uint cnt = 0;
|
||||
void mp_parse_node_free(mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
|
||||
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
uint rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
|
||||
mp_uint_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
mp_uint_t rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
|
||||
if (rule_id == RULE_string) {
|
||||
return;
|
||||
}
|
||||
bool adjust = ADD_BLANK_NODE(rule_id);
|
||||
if (adjust) {
|
||||
n--;
|
||||
}
|
||||
for (uint i = 0; i < n; i++) {
|
||||
cnt += mp_parse_node_free(pns->nodes[i]);
|
||||
for (mp_uint_t i = 0; i < n; i++) {
|
||||
mp_parse_node_free(pns->nodes[i]);
|
||||
}
|
||||
if (adjust) {
|
||||
n++;
|
||||
}
|
||||
m_del_var(mp_parse_node_struct_t, mp_parse_node_t, n, pns);
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
void mp_parse_node_print(mp_parse_node_t pn, int indent) {
|
||||
void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf("[% 4d] ", (int)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
for (int i = 0; i < indent; i++) {
|
||||
for (mp_uint_t i = 0; i < indent; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
printf("NULL\n");
|
||||
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
printf("int(" INT_FMT ")\n", arg);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_INTEGER: printf("int(%s)\n", qstr_str(arg)); break;
|
||||
@@ -219,15 +222,20 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
|
||||
default: assert(0);
|
||||
}
|
||||
} else {
|
||||
// node must be a mp_parse_node_struct_t
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_string) {
|
||||
printf("literal str(%.*s)\n", (int)pns->nodes[1], (char*)pns->nodes[0]);
|
||||
} else {
|
||||
mp_uint_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
#ifdef USE_RULE_NAME
|
||||
printf("%s(%d) (n=%d)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
printf("%s(" UINT_FMT ") (n=" UINT_FMT ")\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (mp_uint_t)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
#else
|
||||
printf("rule(%u) (n=%d)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
printf("rule(" UINT_FMT ") (n=" UINT_FMT ")\n", (mp_uint_t)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
#endif
|
||||
for (uint i = 0; i < n; i++) {
|
||||
mp_parse_node_print(pns->nodes[i], indent + 2);
|
||||
for (mp_uint_t i = 0; i < n; i++) {
|
||||
mp_parse_node_print(pns->nodes[i], indent + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,7 +244,7 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
|
||||
/*
|
||||
STATIC void result_stack_show(parser_t *parser) {
|
||||
printf("result stack, most recent first\n");
|
||||
for (int i = parser->result_stack_top - 1; i >= 0; i--) {
|
||||
for (mp_int_t i = parser->result_stack_top - 1; i >= 0; i--) {
|
||||
mp_parse_node_print(parser->result_stack[i], 0);
|
||||
}
|
||||
}
|
||||
@@ -250,7 +258,7 @@ STATIC mp_parse_node_t pop_result(parser_t *parser) {
|
||||
return parser->result_stack[--parser->result_stack_top];
|
||||
}
|
||||
|
||||
STATIC mp_parse_node_t peek_result(parser_t *parser, int pos) {
|
||||
STATIC mp_parse_node_t peek_result(parser_t *parser, mp_uint_t pos) {
|
||||
if (parser->had_memory_error) {
|
||||
return MP_PARSE_NODE_NULL;
|
||||
}
|
||||
@@ -263,17 +271,32 @@ STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) {
|
||||
return;
|
||||
}
|
||||
if (parser->result_stack_top >= parser->result_stack_alloc) {
|
||||
mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MP_ALLOC_PARSE_RESULT_INC);
|
||||
mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MICROPY_ALLOC_PARSE_RESULT_INC);
|
||||
if (pn == NULL) {
|
||||
memory_error(parser);
|
||||
return;
|
||||
}
|
||||
parser->result_stack = pn;
|
||||
parser->result_stack_alloc += MP_ALLOC_PARSE_RESULT_INC;
|
||||
parser->result_stack_alloc += MICROPY_ALLOC_PARSE_RESULT_INC;
|
||||
}
|
||||
parser->result_stack[parser->result_stack_top++] = pn;
|
||||
}
|
||||
|
||||
STATIC void push_result_string(parser_t *parser, mp_uint_t src_line, const char *str, mp_uint_t len) {
|
||||
mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, 2);
|
||||
if (pn == NULL) {
|
||||
memory_error(parser);
|
||||
return;
|
||||
}
|
||||
pn->source_line = src_line;
|
||||
pn->kind_num_nodes = RULE_string | (2 << 8);
|
||||
char *p = m_new(char, len);
|
||||
memcpy(p, str, len);
|
||||
pn->nodes[0] = (mp_int_t)p;
|
||||
pn->nodes[1] = len;
|
||||
push_result_node(parser, (mp_parse_node_t)pn);
|
||||
}
|
||||
|
||||
STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
const mp_token_t *tok = mp_lexer_cur(lex);
|
||||
mp_parse_node_t pn;
|
||||
@@ -282,20 +305,20 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
} else if (tok->kind == MP_TOKEN_NUMBER) {
|
||||
bool dec = false;
|
||||
bool small_int = true;
|
||||
machine_int_t int_val = 0;
|
||||
int len = tok->len;
|
||||
mp_int_t int_val = 0;
|
||||
mp_uint_t len = tok->len;
|
||||
const char *str = tok->str;
|
||||
int base = 0;
|
||||
int i = mp_parse_num_base(str, len, &base);
|
||||
mp_uint_t base = 0;
|
||||
mp_uint_t i = mp_parse_num_base(str, len, &base);
|
||||
bool overflow = false;
|
||||
for (; i < len; i++) {
|
||||
machine_int_t old_val = int_val;
|
||||
mp_uint_t dig;
|
||||
if (unichar_isdigit(str[i]) && str[i] - '0' < base) {
|
||||
int_val = base * int_val + str[i] - '0';
|
||||
dig = str[i] - '0';
|
||||
} else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') {
|
||||
int_val = base * int_val + str[i] - 'a' + 10;
|
||||
dig = str[i] - 'a' + 10;
|
||||
} else if (base == 16 && 'A' <= str[i] && str[i] <= 'F') {
|
||||
int_val = base * int_val + str[i] - 'A' + 10;
|
||||
dig = str[i] - 'A' + 10;
|
||||
} else if (str[i] == '.' || str[i] == 'e' || str[i] == 'E' || str[i] == 'j' || str[i] == 'J') {
|
||||
dec = true;
|
||||
break;
|
||||
@@ -303,23 +326,41 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
small_int = false;
|
||||
break;
|
||||
}
|
||||
if (int_val < old_val) {
|
||||
// If new value became less than previous, it's overflow
|
||||
// add next digi and check for overflow
|
||||
if (mp_small_int_mul_overflow(int_val, base)) {
|
||||
overflow = true;
|
||||
} else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
|
||||
// If signed number changed sign - it's overflow
|
||||
}
|
||||
int_val = int_val * base + dig;
|
||||
if (!MP_SMALL_INT_FITS(int_val)) {
|
||||
overflow = true;
|
||||
}
|
||||
}
|
||||
if (dec) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn(str, len));
|
||||
} else if (small_int && !overflow && MP_PARSE_FITS_SMALL_INT(int_val)) {
|
||||
} else if (small_int && !overflow && MP_SMALL_INT_FITS(int_val)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val);
|
||||
} else {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn(str, len));
|
||||
}
|
||||
} else if (tok->kind == MP_TOKEN_STRING) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_STRING, qstr_from_strn(tok->str, tok->len));
|
||||
// Don't automatically intern all strings. doc strings (which are usually large)
|
||||
// will be discarded by the compiler, and so we shouldn't intern them.
|
||||
qstr qst = MP_QSTR_NULL;
|
||||
if (tok->len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) {
|
||||
// intern short strings
|
||||
qst = qstr_from_strn(tok->str, tok->len);
|
||||
} else {
|
||||
// check if this string is already interned
|
||||
qst = qstr_find_strn(tok->str, tok->len);
|
||||
}
|
||||
if (qst != MP_QSTR_NULL) {
|
||||
// qstr exists, make a leaf node
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_STRING, qst);
|
||||
} else {
|
||||
// not interned, make a node holding a pointer to the string data
|
||||
push_result_string(parser, mp_lexer_cur(lex)->src_line, tok->str, tok->len);
|
||||
return;
|
||||
}
|
||||
} else if (tok->kind == MP_TOKEN_BYTES) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_BYTES, qstr_from_strn(tok->str, tok->len));
|
||||
} else {
|
||||
@@ -328,7 +369,7 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
push_result_node(parser, pn);
|
||||
}
|
||||
|
||||
STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) {
|
||||
STATIC void push_result_rule(parser_t *parser, mp_uint_t src_line, const rule_t *rule, mp_uint_t num_args) {
|
||||
mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, num_args);
|
||||
if (pn == NULL) {
|
||||
memory_error(parser);
|
||||
@@ -336,7 +377,7 @@ STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule,
|
||||
}
|
||||
pn->source_line = src_line;
|
||||
pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8);
|
||||
for (int i = num_args; i > 0; i--) {
|
||||
for (mp_uint_t i = num_args; i > 0; i--) {
|
||||
pn->nodes[i - 1] = pop_result(parser);
|
||||
}
|
||||
push_result_node(parser, (mp_parse_node_t)pn);
|
||||
@@ -350,11 +391,11 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
|
||||
parser.had_memory_error = false;
|
||||
|
||||
parser.rule_stack_alloc = MP_ALLOC_PARSE_RULE_INIT;
|
||||
parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT;
|
||||
parser.rule_stack_top = 0;
|
||||
parser.rule_stack = m_new_maybe(rule_stack_t, parser.rule_stack_alloc);
|
||||
|
||||
parser.result_stack_alloc = MP_ALLOC_PARSE_RESULT_INIT;
|
||||
parser.result_stack_alloc = MICROPY_ALLOC_PARSE_RESULT_INIT;
|
||||
parser.result_stack_top = 0;
|
||||
parser.result_stack = m_new_maybe(mp_parse_node_t, parser.result_stack_alloc);
|
||||
|
||||
@@ -366,7 +407,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
}
|
||||
|
||||
// work out the top-level rule to use, and push it on the stack
|
||||
int top_level_rule;
|
||||
mp_uint_t top_level_rule;
|
||||
switch (input_kind) {
|
||||
case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break;
|
||||
case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
|
||||
@@ -376,8 +417,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
|
||||
// parse!
|
||||
|
||||
uint n, i; // state for the current rule
|
||||
uint rule_src_line; // source line for the first token matched by the current rule
|
||||
mp_uint_t n, i; // state for the current rule
|
||||
mp_uint_t rule_src_line; // source line for the first token matched by the current rule
|
||||
bool backtrack = false;
|
||||
const rule_t *rule = NULL;
|
||||
mp_token_kind_t tok_kind;
|
||||
@@ -500,7 +541,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
// count number of arguments for the parse_node
|
||||
i = 0;
|
||||
emit_rule = false;
|
||||
for (int x = 0; x < n; ++x) {
|
||||
for (mp_uint_t x = 0; x < n; ++x) {
|
||||
if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
|
||||
tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK;
|
||||
if (tok_kind >= MP_TOKEN_NAME) {
|
||||
@@ -516,14 +557,13 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 && !MICROPY_ENABLE_DOC_STRING
|
||||
// this code discards lonely statement, such as doc strings
|
||||
// problem is that doc strings have already been interned, so this doesn't really help reduce RAM usage
|
||||
#if !MICROPY_EMIT_CPYTHON && !MICROPY_ENABLE_DOC_STRING
|
||||
// this code discards lonely statements, such as doc strings
|
||||
if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
|
||||
mp_parse_node_t p = peek_result(&parser, 1);
|
||||
if (MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) {
|
||||
pop_result(parser);
|
||||
pop_result(parser);
|
||||
if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_string)) {
|
||||
pop_result(&parser);
|
||||
pop_result(&parser);
|
||||
push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0);
|
||||
break;
|
||||
}
|
||||
@@ -549,8 +589,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
i += 1;
|
||||
}
|
||||
|
||||
int num_not_nil = 0;
|
||||
for (int x = 0; x < i; ++x) {
|
||||
mp_uint_t num_not_nil = 0;
|
||||
for (mp_uint_t x = 0; x < i; ++x) {
|
||||
if (peek_result(&parser, x) != MP_PARSE_NODE_NULL) {
|
||||
num_not_nil += 1;
|
||||
}
|
||||
@@ -565,7 +605,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
} else if (num_not_nil == 1) {
|
||||
// single result, leave it on stack
|
||||
mp_parse_node_t pn = MP_PARSE_NODE_NULL;
|
||||
for (int x = 0; x < i; ++x) {
|
||||
for (mp_uint_t x = 0; x < i; ++x) {
|
||||
mp_parse_node_t pn2 = pop_result(&parser);
|
||||
if (pn2 != MP_PARSE_NODE_NULL) {
|
||||
pn = pn2;
|
||||
@@ -613,7 +653,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
}
|
||||
} else {
|
||||
for (;;) {
|
||||
uint arg = rule->arg[i & 1 & n];
|
||||
mp_uint_t arg = rule->arg[i & 1 & n];
|
||||
switch (arg & RULE_ARG_KIND_MASK) {
|
||||
case RULE_ARG_TOK:
|
||||
if (mp_lexer_is_kind(lex, arg & RULE_ARG_ARG_MASK)) {
|
||||
|
||||
19
py/parse.h
19
py/parse.h
@@ -37,13 +37,6 @@ struct _mp_lexer_t;
|
||||
// - xx...x10010: a string of bytes; bits 5 and above are the qstr holding the value
|
||||
// - xx...x10110: a token; bits 5 and above are mp_token_kind_t
|
||||
|
||||
// TODO: these can now be unified with MP_OBJ_FITS_SMALL_INT(x)
|
||||
// makes sure the top 2 bits of x are all cleared (positive number) or all set (negavite number)
|
||||
// these macros can probably go somewhere else because they are used more than just in the parser
|
||||
#define MP_UINT_HIGH_2_BITS (~((~((machine_uint_t)0)) >> 2))
|
||||
// parser's small ints are different from VM small int
|
||||
#define MP_PARSE_FITS_SMALL_INT(x) (((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == 0) || ((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == MP_UINT_HIGH_2_BITS))
|
||||
|
||||
#define MP_PARSE_NODE_NULL (0)
|
||||
#define MP_PARSE_NODE_SMALL_INT (0x1)
|
||||
#define MP_PARSE_NODE_ID (0x02)
|
||||
@@ -53,7 +46,7 @@ struct _mp_lexer_t;
|
||||
#define MP_PARSE_NODE_BYTES (0x12)
|
||||
#define MP_PARSE_NODE_TOKEN (0x16)
|
||||
|
||||
typedef machine_uint_t mp_parse_node_t; // must be pointer size
|
||||
typedef mp_uint_t mp_parse_node_t; // must be pointer size
|
||||
|
||||
typedef struct _mp_parse_node_struct_t {
|
||||
uint32_t source_line; // line number in source file
|
||||
@@ -76,15 +69,15 @@ typedef struct _mp_parse_node_struct_t {
|
||||
|
||||
#define MP_PARSE_NODE_LEAF_KIND(pn) ((pn) & 0x1f)
|
||||
// TODO should probably have int and uint versions of this macro
|
||||
#define MP_PARSE_NODE_LEAF_ARG(pn) (((machine_uint_t)(pn)) >> 5)
|
||||
#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((machine_int_t)(pn)) >> 1)
|
||||
#define MP_PARSE_NODE_LEAF_ARG(pn) (((mp_uint_t)(pn)) >> 5)
|
||||
#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((mp_int_t)(pn)) >> 1)
|
||||
#define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff)
|
||||
#define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8)
|
||||
|
||||
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg);
|
||||
uint mp_parse_node_free(mp_parse_node_t pn);
|
||||
mp_parse_node_t mp_parse_node_new_leaf(mp_int_t kind, mp_int_t arg);
|
||||
void mp_parse_node_free(mp_parse_node_t pn);
|
||||
|
||||
void mp_parse_node_print(mp_parse_node_t pn, int indent);
|
||||
void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent);
|
||||
|
||||
typedef enum {
|
||||
MP_PARSE_SINGLE_INPUT,
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -43,7 +43,7 @@
|
||||
#define STR_INVALID_SYNTAX "invalid syntax"
|
||||
|
||||
void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_kind) {
|
||||
printf(" File \"%s\", line %d, column %d\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
|
||||
printf(" File \"%s\", line " UINT_FMT ", column " UINT_FMT "\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
|
||||
switch (parse_error_kind) {
|
||||
case MP_PARSE_ERROR_MEMORY:
|
||||
printf("MemoryError: %s\n", STR_MEMORY);
|
||||
|
||||
@@ -27,21 +27,25 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "nlr.h"
|
||||
#include "obj.h"
|
||||
#include "parsenumbase.h"
|
||||
#include "parsenum.h"
|
||||
#include "smallint.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
const char *restrict top = str + len;
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str_, mp_uint_t len, mp_uint_t base) {
|
||||
const byte *restrict str = (const byte *)str_;
|
||||
const byte *restrict top = str + len;
|
||||
bool neg = false;
|
||||
mp_obj_t ret_val;
|
||||
|
||||
// check radix base
|
||||
if ((base != 0 && base < 2) || base > 36) {
|
||||
@@ -63,22 +67,22 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
}
|
||||
|
||||
// parse optional base prefix
|
||||
str += mp_parse_num_base(str, top - str, &base);
|
||||
str += mp_parse_num_base((const char*)str, top - str, &base);
|
||||
|
||||
// string should be an integer number
|
||||
machine_int_t int_val = 0;
|
||||
const char *restrict str_val_start = str;
|
||||
mp_int_t int_val = 0;
|
||||
const byte *restrict str_val_start = str;
|
||||
for (; str < top; str++) {
|
||||
machine_int_t old_val = int_val;
|
||||
int dig = *str;
|
||||
// get next digit as a value
|
||||
mp_uint_t dig = *str;
|
||||
if (unichar_isdigit(dig) && dig - '0' < base) {
|
||||
// 0-9 digit
|
||||
int_val = base * int_val + dig - '0';
|
||||
dig = dig - '0';
|
||||
} else if (base == 16) {
|
||||
dig |= 0x20;
|
||||
if ('a' <= dig && dig <= 'f') {
|
||||
// a-f hex digit
|
||||
int_val = base * int_val + dig - 'a' + 10;
|
||||
dig = dig - 'a' + 10;
|
||||
} else {
|
||||
// unknown character
|
||||
break;
|
||||
@@ -87,18 +91,15 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
// unknown character
|
||||
break;
|
||||
}
|
||||
if (int_val < old_val) {
|
||||
// If new value became less than previous, it's overflow
|
||||
goto overflow;
|
||||
} else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
|
||||
// If signed number changed sign - it's overflow
|
||||
|
||||
// add next digi and check for overflow
|
||||
if (mp_small_int_mul_overflow(int_val, base)) {
|
||||
goto overflow;
|
||||
}
|
||||
int_val = int_val * base + dig;
|
||||
if (!MP_SMALL_INT_FITS(int_val)) {
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
|
||||
// check we parsed something
|
||||
if (str == str_val_start) {
|
||||
goto value_error;
|
||||
}
|
||||
|
||||
// negate value if needed
|
||||
@@ -106,6 +107,15 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
int_val = -int_val;
|
||||
}
|
||||
|
||||
// create the small int
|
||||
ret_val = MP_OBJ_NEW_SMALL_INT(int_val);
|
||||
|
||||
have_ret_val:
|
||||
// check we parsed something
|
||||
if (str == str_val_start) {
|
||||
goto value_error;
|
||||
}
|
||||
|
||||
// skip trailing space
|
||||
for (; str < top && unichar_isspace(*str); str++) {
|
||||
}
|
||||
@@ -116,22 +126,29 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
}
|
||||
|
||||
// return the object
|
||||
return MP_OBJ_NEW_SMALL_INT(int_val);
|
||||
|
||||
value_error:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str));
|
||||
return ret_val;
|
||||
|
||||
overflow:
|
||||
// TODO reparse using bignum
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer"));
|
||||
// reparse using long int
|
||||
{
|
||||
const char *s2 = (const char*)str_val_start;
|
||||
ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
|
||||
str = (const byte*)s2;
|
||||
goto have_ret_val;
|
||||
}
|
||||
|
||||
value_error:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d: '%s'", base, str));
|
||||
}
|
||||
|
||||
#define PARSE_DEC_IN_INTG (1)
|
||||
#define PARSE_DEC_IN_FRAC (2)
|
||||
#define PARSE_DEC_IN_EXP (3)
|
||||
typedef enum {
|
||||
PARSE_DEC_IN_INTG,
|
||||
PARSE_DEC_IN_FRAC,
|
||||
PARSE_DEC_IN_EXP,
|
||||
} parse_dec_in_t;
|
||||
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, mp_uint_t len, bool allow_imag, bool force_complex) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
const char *top = str + len;
|
||||
mp_float_t dec_val = 0;
|
||||
bool dec_neg = false;
|
||||
@@ -172,12 +189,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f
|
||||
}
|
||||
} else {
|
||||
// string should be a decimal number
|
||||
int in = PARSE_DEC_IN_INTG;
|
||||
parse_dec_in_t in = PARSE_DEC_IN_INTG;
|
||||
bool exp_neg = false;
|
||||
int exp_val = 0;
|
||||
int exp_extra = 0;
|
||||
mp_int_t exp_val = 0;
|
||||
mp_int_t exp_extra = 0;
|
||||
for (; str < top; str++) {
|
||||
int dig = *str;
|
||||
mp_uint_t dig = *str;
|
||||
if ('0' <= dig && dig <= '9') {
|
||||
dig -= '0';
|
||||
if (in == PARSE_DEC_IN_EXP) {
|
||||
@@ -238,10 +255,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f
|
||||
}
|
||||
|
||||
// return the object
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
if (imag) {
|
||||
return mp_obj_new_complex(0, dec_val);
|
||||
} else if (force_complex) {
|
||||
return mp_obj_new_complex(dec_val, 0);
|
||||
#else
|
||||
if (imag || force_complex) {
|
||||
mp_not_implemented("complex values not supported");
|
||||
#endif
|
||||
} else {
|
||||
return mp_obj_new_float(dec_val);
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base);
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex);
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str, mp_uint_t len, mp_uint_t base);
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, mp_uint_t len, bool allow_imag, bool force_complex);
|
||||
|
||||
@@ -24,15 +24,15 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "parsenumbase.h"
|
||||
|
||||
// find real radix base, and strip preceding '0x', '0o' and '0b'
|
||||
// puts base in *base, and returns number of bytes to skip the prefix
|
||||
int mp_parse_num_base(const char *str, uint len, int *base) {
|
||||
const char *p = str;
|
||||
int c = *(p++);
|
||||
mp_uint_t mp_parse_num_base(const char *str, mp_uint_t len, mp_uint_t *base) {
|
||||
const byte *p = (const byte*)str;
|
||||
unichar c = *(p++);
|
||||
if ((*base == 0 || *base == 16) && c == '0') {
|
||||
c = *(p++);
|
||||
if ((c | 32) == 'x') {
|
||||
@@ -63,6 +63,5 @@ int mp_parse_num_base(const char *str, uint len, int *base) {
|
||||
}
|
||||
p--;
|
||||
}
|
||||
return p - str;
|
||||
return p - (const byte*)str;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
int mp_parse_num_base(const char *str, uint len, int *base);
|
||||
mp_uint_t mp_parse_num_base(const char *str, mp_uint_t len, mp_uint_t *base);
|
||||
|
||||
70
py/pfenv.c
70
py/pfenv.c
@@ -27,8 +27,8 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "mpz.h"
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include "formatfloat.h"
|
||||
#endif
|
||||
|
||||
@@ -91,8 +91,10 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
|
||||
left_pad -= p;
|
||||
}
|
||||
}
|
||||
pfenv->print_strn(pfenv->data, str, len);
|
||||
total_chars_printed += len;
|
||||
if (len) {
|
||||
pfenv->print_strn(pfenv->data, str, len);
|
||||
total_chars_printed += len;
|
||||
}
|
||||
if (right_pad > 0) {
|
||||
total_chars_printed += right_pad;
|
||||
while (right_pad > 0) {
|
||||
@@ -109,14 +111,14 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
|
||||
|
||||
// 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null
|
||||
// We can use 16 characters for 32-bit and 32 characters for 64-bit
|
||||
#define INT_BUF_SIZE (sizeof(machine_int_t) * 4)
|
||||
#define INT_BUF_SIZE (sizeof(mp_int_t) * 4)
|
||||
|
||||
// This function is used by stmhal port to implement printf.
|
||||
// It needs to be a separate function to pfenv_print_mp_int, since converting to a mp_int looses the MSB.
|
||||
int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
|
||||
int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
|
||||
char sign = 0;
|
||||
if (sgn) {
|
||||
if ((machine_int_t)x < 0) {
|
||||
if ((mp_int_t)x < 0) {
|
||||
sign = '-';
|
||||
x = -x;
|
||||
} else if (flags & PF_FLAG_SHOW_SIGN) {
|
||||
@@ -181,13 +183,19 @@ int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, i
|
||||
return len;
|
||||
}
|
||||
|
||||
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
|
||||
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec) {
|
||||
if (!MP_OBJ_IS_INT(x)) {
|
||||
// This will convert booleans to int, or raise an error for
|
||||
// non-integer types.
|
||||
x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x));
|
||||
}
|
||||
|
||||
if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') {
|
||||
if (prec > width) {
|
||||
width = prec;
|
||||
}
|
||||
prec = 0;
|
||||
}
|
||||
char prefix_buf[4];
|
||||
char *prefix = prefix_buf;
|
||||
|
||||
@@ -224,12 +232,15 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
|
||||
|
||||
// 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 = 0;
|
||||
char *str;
|
||||
|
||||
if (prec > 1) {
|
||||
flags |= PF_FLAG_PAD_AFTER_SIGN;
|
||||
}
|
||||
char sign = '\0';
|
||||
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
|
||||
// We add the pad in this function, so since the pad goes after
|
||||
@@ -245,7 +256,39 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
|
||||
x, base, prefix, base_char, comma);
|
||||
}
|
||||
|
||||
int spaces_before = 0;
|
||||
int spaces_after = 0;
|
||||
|
||||
if (prec > 1) {
|
||||
// If prec was specified, then prec specifies the width to zero-pad the
|
||||
// the number to. This zero-padded number then gets left or right
|
||||
// aligned in width characters.
|
||||
|
||||
int prec_width = fmt_size; // The digits
|
||||
if (prec_width < prec) {
|
||||
prec_width = prec;
|
||||
}
|
||||
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
|
||||
if (sign) {
|
||||
prec_width++;
|
||||
}
|
||||
prec_width += prefix_len;
|
||||
}
|
||||
if (prec_width < width) {
|
||||
if (flags & PF_FLAG_LEFT_ADJUST) {
|
||||
spaces_after = width - prec_width;
|
||||
} else {
|
||||
spaces_before = width - prec_width;
|
||||
}
|
||||
}
|
||||
fill = '0';
|
||||
flags &= ~PF_FLAG_LEFT_ADJUST;
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
if (spaces_before) {
|
||||
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_before);
|
||||
}
|
||||
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
|
||||
// pad after sign implies pad after prefix as well.
|
||||
if (sign) {
|
||||
@@ -257,16 +300,23 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
|
||||
width -= prefix_len;
|
||||
}
|
||||
}
|
||||
if (prec > 1) {
|
||||
width = prec;
|
||||
}
|
||||
|
||||
len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width);
|
||||
|
||||
if (spaces_after) {
|
||||
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_after);
|
||||
}
|
||||
|
||||
if (buf != stack_buf) {
|
||||
m_free(buf, buf_size);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec) {
|
||||
char buf[32];
|
||||
char sign = '\0';
|
||||
|
||||
@@ -44,8 +44,8 @@ typedef struct _pfenv_t {
|
||||
void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len);
|
||||
|
||||
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width);
|
||||
int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
|
||||
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
|
||||
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# Note: git describe doesn't work if no tag is available
|
||||
git_tag="$(git describe --dirty --always)"
|
||||
|
||||
3
py/py.mk
3
py/py.mk
@@ -43,6 +43,7 @@ PY_O_BASENAME = \
|
||||
parsenum.o \
|
||||
emitglue.o \
|
||||
runtime.o \
|
||||
stackctrl.o \
|
||||
argcheck.o \
|
||||
map.o \
|
||||
obj.o \
|
||||
@@ -74,6 +75,7 @@ PY_O_BASENAME = \
|
||||
objset.o \
|
||||
objslice.o \
|
||||
objstr.o \
|
||||
objstrunicode.o \
|
||||
objstringio.o \
|
||||
objtuple.o \
|
||||
objtype.o \
|
||||
@@ -100,6 +102,7 @@ PY_O_BASENAME = \
|
||||
repl.o \
|
||||
smallint.o \
|
||||
pfenv.o \
|
||||
../extmod/moductypes.o
|
||||
|
||||
# prepend the build destination prefix to the py object files
|
||||
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
|
||||
|
||||
30
py/qstr.c
30
py/qstr.c
@@ -27,8 +27,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
|
||||
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
|
||||
@@ -55,9 +55,9 @@
|
||||
#define Q_GET_DATA(q) ((q) + 4)
|
||||
|
||||
// this must match the equivalent function in makeqstrdata.py
|
||||
machine_uint_t qstr_compute_hash(const byte *data, uint len) {
|
||||
mp_uint_t qstr_compute_hash(const byte *data, uint len) {
|
||||
// djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html
|
||||
machine_uint_t hash = 5381;
|
||||
mp_uint_t hash = 5381;
|
||||
for (const byte *top = data + len; data < top; data++) {
|
||||
hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data
|
||||
}
|
||||
@@ -77,7 +77,7 @@ typedef struct _qstr_pool_t {
|
||||
const byte *qstrs[];
|
||||
} qstr_pool_t;
|
||||
|
||||
const static qstr_pool_t const_pool = {
|
||||
STATIC const qstr_pool_t const_pool = {
|
||||
NULL, // no previous pool
|
||||
0, // no previous pool
|
||||
10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below)
|
||||
@@ -130,9 +130,9 @@ STATIC qstr qstr_add(const byte *q_ptr) {
|
||||
return last_pool->total_prev_len + last_pool->len - 1;
|
||||
}
|
||||
|
||||
qstr qstr_find_strn(const byte *str, uint str_len) {
|
||||
qstr qstr_find_strn(const char *str, uint str_len) {
|
||||
// work out hash of str
|
||||
machine_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
|
||||
mp_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
|
||||
|
||||
// search pools for the data
|
||||
for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
|
||||
@@ -152,9 +152,9 @@ qstr qstr_from_str(const char *str) {
|
||||
}
|
||||
|
||||
qstr qstr_from_strn(const char *str, uint len) {
|
||||
qstr q = qstr_find_strn((const byte*)str, len);
|
||||
qstr q = qstr_find_strn(str, len);
|
||||
if (q == 0) {
|
||||
machine_uint_t hash = qstr_compute_hash((const byte*)str, len);
|
||||
mp_uint_t hash = qstr_compute_hash((const byte*)str, len);
|
||||
byte *q_ptr = m_new(byte, 4 + len + 1);
|
||||
q_ptr[0] = hash;
|
||||
q_ptr[1] = hash >> 8;
|
||||
@@ -167,12 +167,6 @@ qstr qstr_from_strn(const char *str, uint len) {
|
||||
return q;
|
||||
}
|
||||
|
||||
qstr qstr_from_strn_take(char *str, uint alloc_len, uint len) {
|
||||
qstr q = qstr_from_strn(str, len);
|
||||
m_del(char, str, alloc_len);
|
||||
return q;
|
||||
}
|
||||
|
||||
byte *qstr_build_start(uint len, byte **q_ptr) {
|
||||
assert(len <= 65535);
|
||||
*q_ptr = m_new(byte, 4 + len + 1);
|
||||
@@ -182,10 +176,10 @@ byte *qstr_build_start(uint len, byte **q_ptr) {
|
||||
}
|
||||
|
||||
qstr qstr_build_end(byte *q_ptr) {
|
||||
qstr q = qstr_find_strn(Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr));
|
||||
qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr));
|
||||
if (q == 0) {
|
||||
machine_uint_t len = Q_GET_LENGTH(q_ptr);
|
||||
machine_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
|
||||
mp_uint_t len = Q_GET_LENGTH(q_ptr);
|
||||
mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
|
||||
q_ptr[0] = hash;
|
||||
q_ptr[1] = hash >> 8;
|
||||
q_ptr[4 + len] = '\0';
|
||||
@@ -196,7 +190,7 @@ qstr qstr_build_end(byte *q_ptr) {
|
||||
return q;
|
||||
}
|
||||
|
||||
machine_uint_t qstr_hash(qstr q) {
|
||||
mp_uint_t qstr_hash(qstr q) {
|
||||
return Q_GET_HASH(find_qstr(q));
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user