mirror of
https://github.com/micropython/micropython.git
synced 2025-12-24 13:50:12 +01:00
Compare commits
222 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -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.
|
||||
|
||||
@@ -2,26 +2,29 @@
|
||||
|
||||
// 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_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (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)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
@@ -37,6 +40,8 @@ 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()
|
||||
19
py/bc.h
19
py/bc.h
@@ -36,9 +36,22 @@ 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
|
||||
|
||||
11
py/binary.c
11
py/binary.c
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.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;
|
||||
}
|
||||
}
|
||||
@@ -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':
|
||||
@@ -161,6 +162,8 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
*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 {
|
||||
@@ -217,7 +220,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
|
||||
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;
|
||||
@@ -260,7 +263,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;
|
||||
|
||||
19
py/builtin.c
19
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
|
||||
|
||||
@@ -104,7 +104,7 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
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
|
||||
@@ -172,7 +172,7 @@ 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 (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)"));
|
||||
@@ -391,7 +391,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;
|
||||
}
|
||||
@@ -452,12 +452,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 +471,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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -44,27 +44,29 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ 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 },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray },
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
{ 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 +142,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 = {
|
||||
@@ -159,31 +161,33 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
|
||||
|
||||
{ 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 },
|
||||
#if MICROPY_PY_IO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#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
|
||||
|
||||
// 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 = {
|
||||
|
||||
122
py/compile.c
122
py/compile.c
@@ -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
|
||||
|
||||
@@ -104,7 +105,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
|
||||
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
// Extra constants as defined by a port
|
||||
MICROPY_EXTRA_CONSTANTS
|
||||
MICROPY_PORT_CONSTANTS
|
||||
};
|
||||
|
||||
STATIC const mp_map_t mp_constants_map = {
|
||||
@@ -119,7 +120,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 +134,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];
|
||||
@@ -177,6 +178,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
|
||||
@@ -246,7 +249,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);
|
||||
}
|
||||
@@ -261,7 +264,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -334,7 +337,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
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)) {
|
||||
if (MP_SMALL_INT_FITS(val)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
|
||||
}
|
||||
}
|
||||
@@ -426,6 +429,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 +441,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 +480,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], (machine_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 +497,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 +1035,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 +1051,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 +1164,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 +1747,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 +1846,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);
|
||||
@@ -2058,7 +2077,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 +2518,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 += (machine_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], (machine_uint_t)pns_string->nodes[1]);
|
||||
s_dest += (machine_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
}
|
||||
qstr q = qstr_build_end(q_ptr);
|
||||
|
||||
@@ -2848,15 +2882,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], (machine_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 +3071,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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
16
py/emitbc.c
16
py/emitbc.c
@@ -352,6 +352,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;
|
||||
@@ -617,11 +621,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -704,7 +704,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);
|
||||
}
|
||||
|
||||
@@ -1043,7 +1043,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) {
|
||||
|
||||
10
py/gc.c
10
py/gc.c
@@ -231,7 +231,14 @@ 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++) {
|
||||
@@ -254,6 +261,9 @@ 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:
|
||||
|
||||
24
py/lexer.c
24
py/lexer.c
@@ -64,6 +64,8 @@ struct _mp_lexer_t {
|
||||
mp_token_t tok_cur;
|
||||
};
|
||||
|
||||
uint 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;
|
||||
@@ -211,8 +213,8 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
void indent_push(mp_lexer_t *lex, uint 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;
|
||||
}
|
||||
@@ -303,7 +305,7 @@ STATIC const char *tok_kw[] = {
|
||||
"while",
|
||||
"with",
|
||||
"yield",
|
||||
NULL,
|
||||
"__debug__",
|
||||
};
|
||||
|
||||
STATIC int hex_digit(unichar c) {
|
||||
@@ -687,9 +689,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 (int i = 0; tok_kw[i] != NULL; i++) {
|
||||
for (int i = 0; i < 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 == ARRAY_SIZE(tok_kw) - 1) {
|
||||
// tok_kw[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 +727,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);
|
||||
|
||||
@@ -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 uint mp_optimise_value;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "misc.h"
|
||||
#include "mpconfig.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
|
||||
|
||||
@@ -96,6 +96,8 @@ 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);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#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;
|
||||
@@ -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
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#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) },
|
||||
@@ -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
|
||||
|
||||
@@ -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((machine_uint_t)gc_collected);
|
||||
#else
|
||||
return mp_const_none;
|
||||
#endif
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||
|
||||
|
||||
19
py/modio.c
19
py/modio.c
@@ -30,15 +30,26 @@
|
||||
#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 = {
|
||||
@@ -54,7 +65,7 @@ STATIC const mp_obj_dict_t mp_module_io_globals = {
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#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) \
|
||||
@@ -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 },
|
||||
@@ -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
|
||||
|
||||
102
py/modstruct.c
102
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
|
||||
@@ -34,8 +35,25 @@
|
||||
#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,9 +74,26 @@ STATIC char get_fmt_type(const char **fmt) {
|
||||
return t;
|
||||
}
|
||||
|
||||
STATIC machine_uint_t get_fmt_num(const char **p) {
|
||||
const char *num = *p;
|
||||
uint len = 1;
|
||||
while (unichar_isdigit(*++num)) {
|
||||
len++;
|
||||
}
|
||||
machine_uint_t val = (machine_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) {
|
||||
@@ -66,10 +101,24 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
|
||||
char fmt_type = get_fmt_type(&fmt);
|
||||
machine_uint_t size;
|
||||
for (size = 0; *fmt; fmt++) {
|
||||
uint align;
|
||||
int sz = mp_binary_get_size(fmt_type, *fmt, &align);
|
||||
uint align = 1;
|
||||
machine_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');
|
||||
}
|
||||
|
||||
machine_uint_t sz;
|
||||
if (*fmt == 's') {
|
||||
sz = cnt;
|
||||
} else {
|
||||
sz = (machine_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
|
||||
}
|
||||
// TODO
|
||||
assert(sz != -1);
|
||||
assert(sz != (machine_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);
|
||||
machine_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);
|
||||
machine_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);
|
||||
machine_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;
|
||||
}
|
||||
|
||||
12
py/modsys.c
12
py/modsys.c
@@ -34,7 +34,7 @@
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
|
||||
// These should be implemented by ports, specific types don't matter,
|
||||
// only addresses.
|
||||
@@ -51,6 +51,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 +62,20 @@ 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_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 },
|
||||
|
||||
244
py/mpconfig.h
244
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)
|
||||
@@ -135,13 +158,13 @@
|
||||
#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 +212,15 @@ 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)
|
||||
#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)
|
||||
#define MICROPY_PY_BUILTINS_FLOAT (0)
|
||||
#endif
|
||||
|
||||
// Enable features which improve CPython compatibility
|
||||
@@ -269,36 +231,110 @@ 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 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 "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.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
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
82
py/mpz.c
82
py/mpz.c
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
2
py/mpz.h
2
py/mpz.h
@@ -98,7 +98,7 @@ 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
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
|
||||
19
py/obj.c
19
py/obj.c
@@ -122,7 +122,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;
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,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 +222,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) {
|
||||
machine_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].
|
||||
@@ -242,7 +242,7 @@ 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) {
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value) {
|
||||
if (arg == mp_const_false) {
|
||||
*value = 0;
|
||||
} else if (arg == mp_const_true) {
|
||||
@@ -257,7 +257,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;
|
||||
@@ -357,12 +357,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t 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 +368,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?
|
||||
|
||||
78
py/obj.h
78
py/obj.h
@@ -52,8 +52,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,22 +62,16 @@ 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)
|
||||
@@ -158,7 +151,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, machine_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);
|
||||
@@ -177,7 +170,7 @@ typedef struct _mp_set_t {
|
||||
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, machine_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);
|
||||
@@ -246,6 +239,7 @@ typedef struct _mp_stream_p_t {
|
||||
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);
|
||||
// add seek() ?
|
||||
int is_bytes : 1;
|
||||
} mp_stream_p_t;
|
||||
|
||||
struct _mp_obj_type_t {
|
||||
@@ -255,15 +249,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 +315,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 +340,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;
|
||||
@@ -371,11 +367,11 @@ 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_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 +380,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);
|
||||
@@ -422,9 +418,9 @@ bool mp_obj_is_callable(mp_obj_t o_in);
|
||||
machine_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
|
||||
machine_int_t mp_obj_get_int(mp_const_obj_t arg);
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_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
|
||||
@@ -445,12 +441,12 @@ 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
|
||||
machine_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);
|
||||
machine_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)
|
||||
@@ -472,20 +468,21 @@ 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);
|
||||
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);
|
||||
|
||||
#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
|
||||
@@ -509,6 +506,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 +515,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 +534,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 +559,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 {
|
||||
machine_uint_t start;
|
||||
machine_uint_t stop;
|
||||
machine_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(machine_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 +585,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
|
||||
@@ -139,7 +140,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 +166,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) {
|
||||
|
||||
@@ -76,7 +76,7 @@ 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_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_bool = {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
126
py/objdict.c
126
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;
|
||||
}
|
||||
|
||||
@@ -103,7 +76,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t 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;
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (machine_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);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -120,12 +120,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 +157,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 +183,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 +283,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 +96,7 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,9 +165,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
|
||||
|
||||
302
py/objfun.c
302
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"
|
||||
@@ -58,7 +58,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 +153,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 +193,32 @@ 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) {
|
||||
// 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(machine_uint_t))
|
||||
|
||||
// Set this to enable a simple stack overflow check.
|
||||
#define VM_DETECT_STACK_OVERFLOW (0)
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
machine_uint_t n_state = code_state->n_state;
|
||||
const byte *ip = code_state->ip;
|
||||
|
||||
assert(n_kw == 0);
|
||||
assert(self->n_kwonly_args == 0);
|
||||
assert(self->takes_var_args == 0);
|
||||
assert(self->takes_kw_args == 0);
|
||||
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;
|
||||
|
||||
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) {
|
||||
// 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);
|
||||
// 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 +228,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 +285,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 +333,122 @@ 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) {
|
||||
// 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.
|
||||
|
||||
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
|
||||
machine_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
|
||||
machine_uint_t n_state = ip[0] | (ip[1] << 8);
|
||||
machine_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 +466,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 +475,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 +485,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;
|
||||
}
|
||||
@@ -468,7 +530,7 @@ STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
} 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);
|
||||
|
||||
@@ -30,10 +30,15 @@ typedef struct _mp_obj_fun_bc_t {
|
||||
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 has_def_kw_args : 1; // set if this function has default keyword args
|
||||
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)
|
||||
// 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
|
||||
machine_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
|
||||
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 = 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;
|
||||
}
|
||||
|
||||
33
py/objint.c
33
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]))));
|
||||
#endif
|
||||
} else {
|
||||
// try to convert to small int (eg from bool)
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
|
||||
}
|
||||
|
||||
@@ -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,7 +144,7 @@ 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;
|
||||
const mp_obj_int_t *self = self_in;
|
||||
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
|
||||
num = self->val;
|
||||
#else
|
||||
@@ -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;
|
||||
}
|
||||
@@ -247,22 +252,22 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value) {
|
||||
if (MP_OBJ_FITS_SMALL_INT(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) {
|
||||
machine_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) {
|
||||
machine_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
|
||||
|
||||
@@ -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"
|
||||
@@ -63,7 +65,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 +78,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,12 +136,12 @@ 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)) {
|
||||
if (MP_SMALL_INT_FITS(value)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
return mp_obj_new_int_from_ll(value);
|
||||
@@ -161,36 +163,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) {
|
||||
machine_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) {
|
||||
machine_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"
|
||||
@@ -58,10 +59,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 +91,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 +109,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,7 +118,7 @@ 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);
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
|
||||
@@ -129,7 +130,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);
|
||||
@@ -213,7 +214,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 +234,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)) {
|
||||
if (MP_SMALL_INT_FITS(value)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
return mp_obj_new_int_from_ll(value);
|
||||
@@ -260,35 +261,27 @@ 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) {
|
||||
machine_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) {
|
||||
machine_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;
|
||||
const mp_obj_int_t *self = self_in;
|
||||
machine_int_t value;
|
||||
if (mpz_as_int_checked(&self->mpz, &value)) {
|
||||
return value;
|
||||
@@ -299,7 +292,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);
|
||||
|
||||
61
py/objlist.c
61
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,7 +121,7 @@ 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;
|
||||
@@ -129,7 +129,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
machine_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
|
||||
|
||||
@@ -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
|
||||
|
||||
24
py/objset.c
24
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;
|
||||
@@ -52,13 +54,13 @@ 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, ")");
|
||||
}
|
||||
@@ -475,7 +477,7 @@ STATIC mp_obj_t set_unary_op(int op, mp_obj_t 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;
|
||||
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
|
||||
|
||||
391
py/objstr.c
391
py/objstr.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
|
||||
@@ -37,8 +38,9 @@
|
||||
#include "runtime.h"
|
||||
#include "pfenv.h"
|
||||
#include "objstr.h"
|
||||
#include "objlist.h"
|
||||
|
||||
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args);
|
||||
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict);
|
||||
const mp_obj_t mp_const_empty_bytes;
|
||||
|
||||
// use this macro to extract the string hash
|
||||
@@ -52,7 +54,6 @@ const mp_obj_t mp_const_empty_bytes;
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
|
||||
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
|
||||
STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len);
|
||||
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
|
||||
STATIC NORETURN void arg_type_mixup();
|
||||
|
||||
@@ -67,7 +68,7 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
|
||||
// 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_single_quote || !has_double_quote) && s < top; s++) {
|
||||
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 == '"') {
|
||||
@@ -127,7 +128,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
|
||||
{
|
||||
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((byte*)vstr->buf, vstr->len, false);
|
||||
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
@@ -141,7 +142,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
|
||||
}
|
||||
GET_STR_DATA_LEN(args[0], str_data, str_len);
|
||||
GET_STR_HASH(args[0], str_hash);
|
||||
mp_obj_str_t *o = str_new(&mp_type_str, NULL, str_len);
|
||||
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;
|
||||
@@ -169,7 +170,7 @@ STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
|
||||
}
|
||||
GET_STR_DATA_LEN(args[0], str_data, str_len);
|
||||
GET_STR_HASH(args[0], str_hash);
|
||||
mp_obj_str_t *o = str_new(&mp_type_bytes, NULL, str_len);
|
||||
mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len);
|
||||
o->data = str_data;
|
||||
o->hash = str_hash;
|
||||
return o;
|
||||
@@ -294,7 +295,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
if (!MP_OBJ_IS_SMALL_INT(rhs_in)) {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
int n = MP_OBJ_SMALL_INT_VALUE(rhs_in);
|
||||
byte *data;
|
||||
@@ -306,14 +307,19 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
case MP_BINARY_OP_MODULO: {
|
||||
mp_obj_t *args;
|
||||
uint n_args;
|
||||
mp_obj_t dict = MP_OBJ_NULL;
|
||||
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) {
|
||||
// TODO: Support tuple subclasses?
|
||||
mp_obj_tuple_get(rhs_in, &n_args, &args);
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) {
|
||||
args = NULL;
|
||||
n_args = 0;
|
||||
dict = rhs_in;
|
||||
} else {
|
||||
args = &rhs_in;
|
||||
n_args = 1;
|
||||
}
|
||||
return str_modulo_format(lhs_in, n_args, args);
|
||||
return str_modulo_format(lhs_in, n_args, args, dict);
|
||||
}
|
||||
|
||||
//case MP_BINARY_OP_NOT_EQUAL: // This is never passed here
|
||||
@@ -326,9 +332,20 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len);
|
||||
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len));
|
||||
}
|
||||
if (lhs_type == &mp_type_bytes) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) {
|
||||
goto uncomparable;
|
||||
}
|
||||
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, bufinfo.buf, bufinfo.len));
|
||||
}
|
||||
uncomparable:
|
||||
if (op == MP_BINARY_OP_EQUAL) {
|
||||
return mp_const_false;
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
@@ -336,23 +353,24 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
#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"));
|
||||
}
|
||||
return str_new(type, self_data + start, stop - start);
|
||||
return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);
|
||||
}
|
||||
#endif
|
||||
uint index_val = mp_get_index(type, self_len, index, false);
|
||||
if (type == &mp_type_bytes) {
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self_data[index_val]);
|
||||
} else {
|
||||
return mp_obj_new_str(self_data + index_val, 1, true);
|
||||
return mp_obj_new_str((char*)self_data + index_val, 1, true);
|
||||
}
|
||||
} else {
|
||||
return MP_OBJ_NOT_SUPPORTED;
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +451,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
|
||||
while (s < top && splits != 0) {
|
||||
const byte *start = s;
|
||||
while (s < top && !is_ws(*s)) s++;
|
||||
mp_obj_list_append(res, str_new(self_type, start, s - start));
|
||||
mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));
|
||||
if (s >= top) {
|
||||
break;
|
||||
}
|
||||
@@ -444,7 +462,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
|
||||
if (s < top) {
|
||||
mp_obj_list_append(res, str_new(self_type, s, top - s));
|
||||
mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, s, top - s));
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -468,7 +486,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
s++;
|
||||
}
|
||||
mp_obj_list_append(res, str_new(self_type, start, s - start));
|
||||
mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));
|
||||
if (s >= top) {
|
||||
break;
|
||||
}
|
||||
@@ -482,6 +500,68 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
|
||||
return res;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args < 3) {
|
||||
// If we don't have split limit, it doesn't matter from which side
|
||||
// we split.
|
||||
return str_split(n_args, args);
|
||||
}
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
mp_obj_t sep = args[1];
|
||||
GET_STR_DATA_LEN(args[0], s, len);
|
||||
|
||||
machine_int_t splits = mp_obj_get_int(args[2]);
|
||||
machine_int_t org_splits = splits;
|
||||
// Preallocate list to the max expected # of elements, as we
|
||||
// will fill it from the end.
|
||||
mp_obj_list_t *res = mp_obj_new_list(splits + 1, NULL);
|
||||
int idx = splits;
|
||||
|
||||
if (sep == mp_const_none) {
|
||||
assert(!"TODO: rsplit(None,n) not implemented");
|
||||
} else {
|
||||
uint sep_len;
|
||||
const char *sep_str = mp_obj_str_get_data(sep, &sep_len);
|
||||
|
||||
if (sep_len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator"));
|
||||
}
|
||||
|
||||
const byte *beg = s;
|
||||
const byte *last = s + len;
|
||||
for (;;) {
|
||||
s = last - sep_len;
|
||||
for (;;) {
|
||||
if (splits == 0 || s < beg) {
|
||||
break;
|
||||
} else if (memcmp(s, sep_str, sep_len) == 0) {
|
||||
break;
|
||||
}
|
||||
s--;
|
||||
}
|
||||
if (s < beg || splits == 0) {
|
||||
res->items[idx] = mp_obj_new_str_of_type(self_type, beg, last - beg);
|
||||
break;
|
||||
}
|
||||
res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len);
|
||||
last = s;
|
||||
if (splits > 0) {
|
||||
splits--;
|
||||
}
|
||||
}
|
||||
if (idx != 0) {
|
||||
// We split less parts than split limit, now go cleanup surplus
|
||||
int used = org_splits + 1 - idx;
|
||||
memcpy(res->items, &res->items[idx], used * sizeof(mp_obj_t));
|
||||
mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items));
|
||||
res->len = used;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction, bool is_index) {
|
||||
assert(2 <= n_args && n_args <= 4);
|
||||
assert(MP_OBJ_IS_STR(args[0]));
|
||||
@@ -530,13 +610,28 @@ STATIC mp_obj_t str_rindex(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
|
||||
// TODO: (Much) more variety in args
|
||||
STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) {
|
||||
GET_STR_DATA_LEN(self_in, str, str_len);
|
||||
GET_STR_DATA_LEN(arg, prefix, prefix_len);
|
||||
if (prefix_len > str_len) {
|
||||
STATIC mp_obj_t str_startswith(uint n_args, const mp_obj_t *args) {
|
||||
GET_STR_DATA_LEN(args[0], str, str_len);
|
||||
GET_STR_DATA_LEN(args[1], prefix, prefix_len);
|
||||
uint index_val = 0;
|
||||
if (n_args > 2) {
|
||||
index_val = mp_get_index(&mp_type_str, str_len, args[2], true);
|
||||
}
|
||||
if (prefix_len + index_val > str_len) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return MP_BOOL(memcmp(str, prefix, prefix_len) == 0);
|
||||
return MP_BOOL(memcmp(str + index_val, prefix, prefix_len) == 0);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_endswith(uint n_args, const mp_obj_t *args) {
|
||||
GET_STR_DATA_LEN(args[0], str, str_len);
|
||||
GET_STR_DATA_LEN(args[1], suffix, suffix_len);
|
||||
assert(n_args == 2);
|
||||
|
||||
if (suffix_len > str_len) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return MP_BOOL(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0);
|
||||
}
|
||||
|
||||
enum { LSTRIP, RSTRIP, STRIP };
|
||||
@@ -576,6 +671,7 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
|
||||
for (machine_uint_t len = orig_str_len; len > 0; len--) {
|
||||
if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) {
|
||||
if (!first_good_char_pos_set) {
|
||||
first_good_char_pos_set = true;
|
||||
first_good_char_pos = i;
|
||||
if (type == LSTRIP) {
|
||||
last_good_char_pos = orig_str_len - 1;
|
||||
@@ -585,14 +681,13 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
|
||||
last_good_char_pos = i;
|
||||
break;
|
||||
}
|
||||
first_good_char_pos_set = true;
|
||||
}
|
||||
last_good_char_pos = i;
|
||||
}
|
||||
i += delta;
|
||||
}
|
||||
|
||||
if (first_good_char_pos == 0 && last_good_char_pos == 0) {
|
||||
if (!first_good_char_pos_set) {
|
||||
// string is all whitespace, return ''
|
||||
return MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
}
|
||||
@@ -600,7 +695,13 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
|
||||
assert(last_good_char_pos >= first_good_char_pos);
|
||||
//+1 to accomodate the last character
|
||||
machine_uint_t stripped_len = last_good_char_pos - first_good_char_pos + 1;
|
||||
return str_new(self_type, orig_str + first_good_char_pos, stripped_len);
|
||||
if (stripped_len == orig_str_len) {
|
||||
// If nothing was stripped, don't bother to dup original string
|
||||
// TODO: watch out for this case when we'll get to bytearray.strip()
|
||||
assert(first_good_char_pos == 0);
|
||||
return args[0];
|
||||
}
|
||||
return mp_obj_new_str_of_type(self_type, orig_str + first_good_char_pos, stripped_len);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_strip(uint n_args, const mp_obj_t *args) {
|
||||
@@ -644,14 +745,14 @@ static bool arg_looks_integer(mp_obj_t arg) {
|
||||
|
||||
static bool arg_looks_numeric(mp_obj_t arg) {
|
||||
return arg_looks_integer(arg)
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
|| MP_OBJ_IS_TYPE(arg, &mp_type_float)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
static mp_obj_t arg_as_int(mp_obj_t arg) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
|
||||
|
||||
// TODO: Needs a way to construct an mpz integer from a float
|
||||
@@ -680,7 +781,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
vstr_add_char(vstr, '}');
|
||||
continue;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Single '}' encountered in format string"));
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "single '}' encountered in format string"));
|
||||
}
|
||||
if (*str != '{') {
|
||||
vstr_add_char(vstr, *str);
|
||||
@@ -726,7 +827,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
// '{:d}'.format(True) returns '1'
|
||||
// So we treat {:} as {} and this later gets treated to be {!s}
|
||||
if (*str != '}') {
|
||||
format_spec = vstr_new();
|
||||
format_spec = vstr_new();
|
||||
while (str < top && *str != '}') {
|
||||
vstr_add_char(format_spec, *str++);
|
||||
}
|
||||
@@ -744,7 +845,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
if (field_name) {
|
||||
if (arg_i > 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from automatic field numbering to manual field specification"));
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't switch from automatic field numbering to manual field specification"));
|
||||
}
|
||||
int index = 0;
|
||||
if (str_to_int(vstr_str(field_name), &index) != vstr_len(field_name) - 1) {
|
||||
@@ -759,7 +860,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
field_name = NULL;
|
||||
} else {
|
||||
if (arg_i < 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from manual field specification to automatic field numbering"));
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't switch from manual field specification to automatic field numbering"));
|
||||
}
|
||||
if (arg_i >= n_args - 1) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range"));
|
||||
@@ -777,11 +878,11 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
} else if (conversion == 'r') {
|
||||
print_kind = PRINT_REPR;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown conversion specifier %c", conversion));
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown conversion specifier %c", conversion));
|
||||
}
|
||||
vstr_t *arg_vstr = vstr_new();
|
||||
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, arg_vstr, arg, print_kind);
|
||||
arg = mp_obj_new_str((const byte *)vstr_str(arg_vstr), vstr_len(arg_vstr), false);
|
||||
arg = mp_obj_new_str(vstr_str(arg_vstr), vstr_len(arg_vstr), false);
|
||||
vstr_free(arg_vstr);
|
||||
}
|
||||
|
||||
@@ -880,7 +981,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
if (arg_looks_integer(arg)) {
|
||||
switch (type) {
|
||||
case 'b':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width);
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width, 0);
|
||||
continue;
|
||||
|
||||
case 'c':
|
||||
@@ -893,7 +994,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
case '\0': // No explicit format type implies 'd'
|
||||
case 'n': // I don't think we support locales in uPy so use 'd'
|
||||
case 'd':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width);
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width, 0);
|
||||
continue;
|
||||
|
||||
case 'o':
|
||||
@@ -901,15 +1002,12 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
flags |= PF_FLAG_SHOW_OCTAL_LETTER;
|
||||
}
|
||||
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width);
|
||||
continue;
|
||||
|
||||
case 'x':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, 'a', flags, fill, width);
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, 0);
|
||||
continue;
|
||||
|
||||
case 'X':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, 'A', flags, fill, width);
|
||||
case 'x':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width, 0);
|
||||
continue;
|
||||
|
||||
case 'e':
|
||||
@@ -925,7 +1023,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
|
||||
"Unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg)));
|
||||
"unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,7 +1035,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
// Even though the docs say that an unspecified type is the same
|
||||
// as 'g', there is one subtle difference, when the exponent
|
||||
// is one less than the precision.
|
||||
//
|
||||
//
|
||||
// '{:10.1}'.format(0.0) ==> '0e+00'
|
||||
// '{:10.1g}'.format(0.0) ==> '0'
|
||||
//
|
||||
@@ -969,14 +1067,14 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
flags |= PF_FLAG_PAD_NAN_INF; // '{:06e}'.format(float('-inf')) should give '-00inf'
|
||||
switch (type) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision);
|
||||
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
@@ -987,7 +1085,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
|
||||
"Unknown format code '%c' for object of type 'float'",
|
||||
"unknown format code '%c' for object of type 'float'",
|
||||
type, mp_obj_get_type_str(arg)));
|
||||
}
|
||||
} else {
|
||||
@@ -1018,18 +1116,18 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
|
||||
"Unknown format code '%c' for object of type 'str'",
|
||||
"unknown format code '%c' for object of type 'str'",
|
||||
type, mp_obj_get_type_str(arg)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict) {
|
||||
assert(MP_OBJ_IS_STR(pattern));
|
||||
|
||||
GET_STR_DATA_LEN(pattern, str, len);
|
||||
@@ -1041,6 +1139,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
pfenv_vstr.print_strn = pfenv_vstr_add_strn;
|
||||
|
||||
for (const byte *top = str + len; str < top; str++) {
|
||||
mp_obj_t arg = MP_OBJ_NULL;
|
||||
if (*str != '%') {
|
||||
vstr_add_char(vstr, *str);
|
||||
continue;
|
||||
@@ -1052,17 +1151,29 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
vstr_add_char(vstr, '%');
|
||||
continue;
|
||||
}
|
||||
if (arg_i >= n_args) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
|
||||
|
||||
// Dictionary value lookup
|
||||
if (*str == '(') {
|
||||
const byte *key = ++str;
|
||||
while (*str != ')') {
|
||||
if (str >= top) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format key"));
|
||||
}
|
||||
++str;
|
||||
}
|
||||
mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true);
|
||||
arg = mp_obj_dict_get(dict, k_obj);
|
||||
str++;
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
char fill = ' ';
|
||||
bool alt = false;
|
||||
int alt = 0;
|
||||
while (str < top) {
|
||||
if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST;
|
||||
else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN;
|
||||
else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN;
|
||||
else if (*str == '#') alt = true;
|
||||
else if (*str == '#') alt = PF_FLAG_SHOW_PREFIX;
|
||||
else if (*str == '0') {
|
||||
flags |= PF_FLAG_PAD_AFTER_SIGN;
|
||||
fill = '0';
|
||||
@@ -1070,9 +1181,12 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
str++;
|
||||
}
|
||||
// parse width, if it exists
|
||||
int width = 0;
|
||||
int width = 0;
|
||||
if (str < top) {
|
||||
if (*str == '*') {
|
||||
if (arg_i >= n_args) {
|
||||
goto not_enough_args;
|
||||
}
|
||||
width = mp_obj_get_int(args[arg_i++]);
|
||||
str++;
|
||||
} else {
|
||||
@@ -1085,6 +1199,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
if (str < top && *str == '.') {
|
||||
if (++str < top) {
|
||||
if (*str == '*') {
|
||||
if (arg_i >= n_args) {
|
||||
goto not_enough_args;
|
||||
}
|
||||
prec = mp_obj_get_int(args[arg_i++]);
|
||||
str++;
|
||||
} else {
|
||||
@@ -1099,14 +1216,22 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
if (str >= top) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format"));
|
||||
}
|
||||
mp_obj_t arg = args[arg_i];
|
||||
|
||||
// Tuple value lookup
|
||||
if (arg == MP_OBJ_NULL) {
|
||||
if (arg_i >= n_args) {
|
||||
not_enough_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
|
||||
}
|
||||
arg = args[arg_i++];
|
||||
}
|
||||
switch (*str) {
|
||||
case 'c':
|
||||
if (MP_OBJ_IS_STR(arg)) {
|
||||
uint len;
|
||||
const char *s = mp_obj_str_get_data(arg, &len);
|
||||
if (len != 1) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "%c requires int or char"));
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "%%c requires int or char"));
|
||||
break;
|
||||
}
|
||||
pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width);
|
||||
@@ -1117,23 +1242,23 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, ' ', width);
|
||||
break;
|
||||
}
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
// This is what CPython reports, so we report the same.
|
||||
if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float"));
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float"));
|
||||
|
||||
}
|
||||
#endif
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required"));
|
||||
break;
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required"));
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width);
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width, prec);
|
||||
break;
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
@@ -1148,7 +1273,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
if (alt) {
|
||||
flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);
|
||||
}
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 8, 'a', flags, fill, width);
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, prec);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
@@ -1169,18 +1294,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x':
|
||||
if (alt) {
|
||||
flags |= PF_FLAG_SHOW_PREFIX;
|
||||
}
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'a', flags, fill, width);
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
if (alt) {
|
||||
flags |= PF_FLAG_SHOW_PREFIX;
|
||||
}
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'A', flags, fill, width);
|
||||
case 'x':
|
||||
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1188,14 +1304,13 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
|
||||
"unsupported format character '%c' (0x%x) at index %d",
|
||||
*str, *str, str - start_str));
|
||||
}
|
||||
arg_i++;
|
||||
}
|
||||
|
||||
if (arg_i != n_args) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting"));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1363,9 +1478,9 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t di
|
||||
const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction);
|
||||
if (position_ptr != NULL) {
|
||||
machine_uint_t position = position_ptr - str;
|
||||
result[0] = str_new(self_type, str, position);
|
||||
result[0] = mp_obj_new_str_of_type(self_type, str, position);
|
||||
result[1] = arg;
|
||||
result[2] = str_new(self_type, str + position + sep_len, str_len - position - sep_len);
|
||||
result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len);
|
||||
}
|
||||
|
||||
return mp_obj_new_tuple(3, result);
|
||||
@@ -1379,30 +1494,77 @@ STATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) {
|
||||
return str_partitioner(self_in, arg, -1);
|
||||
}
|
||||
|
||||
enum { CASE_UPPER, CASE_LOWER };
|
||||
|
||||
// Supposedly not too critical operations, so optimize for code size
|
||||
STATIC mp_obj_t str_caseconv(int op, mp_obj_t self_in) {
|
||||
STATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) {
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
byte *data;
|
||||
mp_obj_t s = mp_obj_str_builder_start(mp_obj_get_type(self_in), self_len, &data);
|
||||
for (int i = 0; i < self_len; i++) {
|
||||
if (op == CASE_UPPER) {
|
||||
*data++ = unichar_toupper(*self_data++);
|
||||
} else {
|
||||
*data++ = unichar_tolower(*self_data++);
|
||||
}
|
||||
*data++ = op(*self_data++);
|
||||
}
|
||||
*data = 0;
|
||||
return mp_obj_str_builder_end(s);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_lower(mp_obj_t self_in) {
|
||||
return str_caseconv(CASE_LOWER, self_in);
|
||||
return str_caseconv(unichar_tolower, self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_upper(mp_obj_t self_in) {
|
||||
return str_caseconv(CASE_UPPER, self_in);
|
||||
return str_caseconv(unichar_toupper, self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) {
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
|
||||
if (self_len == 0) {
|
||||
return mp_const_false; // default to False for empty str
|
||||
}
|
||||
|
||||
if (f != unichar_isupper && f != unichar_islower) {
|
||||
for (int i = 0; i < self_len; i++) {
|
||||
if (!f(*self_data++)) {
|
||||
return mp_const_false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool contains_alpha = false;
|
||||
|
||||
for (int i = 0; i < self_len; i++) { // only check alphanumeric characters
|
||||
if (unichar_isalpha(*self_data++)) {
|
||||
contains_alpha = true;
|
||||
if (!f(*(self_data - 1))) { // -1 because we already incremented above
|
||||
return mp_const_false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!contains_alpha) {
|
||||
return mp_const_false;
|
||||
}
|
||||
}
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_isspace(mp_obj_t self_in) {
|
||||
return str_uni_istype(unichar_isspace, self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_isalpha(mp_obj_t self_in) {
|
||||
return str_uni_istype(unichar_isalpha, self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_isdigit(mp_obj_t self_in) {
|
||||
return str_uni_istype(unichar_isdigit, self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_isupper(mp_obj_t self_in) {
|
||||
return str_uni_istype(unichar_isupper, self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_islower(mp_obj_t self_in) {
|
||||
return str_uni_istype(unichar_islower, self_in);
|
||||
}
|
||||
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
@@ -1459,7 +1621,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);
|
||||
@@ -1470,6 +1634,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
|
||||
|
||||
STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
@@ -1482,7 +1651,9 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
{ 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 },
|
||||
@@ -1493,6 +1664,11 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
{ 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);
|
||||
@@ -1545,7 +1721,7 @@ mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) {
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
|
||||
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len) {
|
||||
mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
|
||||
o->base.type = type;
|
||||
o->len = len;
|
||||
@@ -1559,22 +1735,29 @@ STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_str(const byte* data, uint len, bool make_qstr_if_not_already) {
|
||||
qstr q = qstr_find_strn(data, len);
|
||||
if (q != MP_QSTR_NULL) {
|
||||
// qstr with this data already exists
|
||||
return MP_OBJ_NEW_QSTR(q);
|
||||
} else if (make_qstr_if_not_already) {
|
||||
// no existing qstr, make a new one
|
||||
return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len));
|
||||
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already) {
|
||||
if (make_qstr_if_not_already) {
|
||||
// use existing, or make a new qstr
|
||||
return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len));
|
||||
} else {
|
||||
// no existing qstr, don't make one
|
||||
return str_new(&mp_type_str, data, len);
|
||||
qstr q = qstr_find_strn(data, len);
|
||||
if (q != MP_QSTR_NULL) {
|
||||
// qstr with this data already exists
|
||||
return MP_OBJ_NEW_QSTR(q);
|
||||
} else {
|
||||
// no existing qstr, don't make one
|
||||
return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_str_intern(mp_obj_t str) {
|
||||
GET_STR_DATA_LEN(str, data, len);
|
||||
return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len));
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_bytes(const byte* data, uint len) {
|
||||
return str_new(&mp_type_bytes, data, len);
|
||||
return mp_obj_new_str_of_type(&mp_type_bytes, data, len);
|
||||
}
|
||||
|
||||
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
|
||||
@@ -1672,7 +1855,7 @@ 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) {
|
||||
mp_obj_t o_out = mp_obj_new_str(str + self->cur, 1, true);
|
||||
mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true);
|
||||
self->cur += 1;
|
||||
return o_out;
|
||||
} else {
|
||||
|
||||
@@ -36,3 +36,4 @@ typedef struct _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};
|
||||
|
||||
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);
|
||||
|
||||
@@ -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,8 +35,9 @@
|
||||
#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;
|
||||
@@ -46,7 +48,7 @@ typedef struct _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) {
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
302
py/objtype.c
302
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
|
||||
@@ -48,8 +49,10 @@
|
||||
/******************************************************************************/
|
||||
// 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 +98,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;
|
||||
machine_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 +126,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 +177,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 +197,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 +234,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 +244,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 +330,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 +377,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 +395,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 +404,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 +425,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 +459,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 +480,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 +502,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 +542,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 +576,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 +603,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 +684,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 +730,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,15 +830,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 = {
|
||||
|
||||
104
py/parse.c
104
py/parse.c
@@ -28,6 +28,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#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)
|
||||
@@ -134,13 +137,13 @@ STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int ar
|
||||
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;
|
||||
@@ -170,26 +173,26 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
|
||||
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);
|
||||
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]);
|
||||
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
|
||||
@@ -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 {
|
||||
uint 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(%d) (n=%d)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
#else
|
||||
printf("rule(%u) (n=%d)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
printf("rule(%u) (n=%d)\n", (uint)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 (uint i = 0; i < n; i++) {
|
||||
mp_parse_node_print(pns->nodes[i], indent + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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, int src_line, const char *str, uint 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] = (machine_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;
|
||||
@@ -289,13 +312,13 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
int i = mp_parse_num_base(str, len, &base);
|
||||
bool overflow = false;
|
||||
for (; i < len; i++) {
|
||||
machine_int_t old_val = int_val;
|
||||
int 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 {
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
@@ -82,7 +75,7 @@ typedef struct _mp_parse_node_struct_t {
|
||||
#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);
|
||||
void mp_parse_node_free(mp_parse_node_t pn);
|
||||
|
||||
void mp_parse_node_print(mp_parse_node_t pn, int indent);
|
||||
|
||||
|
||||
@@ -34,14 +34,16 @@
|
||||
#include "obj.h"
|
||||
#include "parsenumbase.h"
|
||||
#include "parsenum.h"
|
||||
#include "smallint.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;
|
||||
bool neg = false;
|
||||
mp_obj_t ret_val;
|
||||
|
||||
// check radix base
|
||||
if ((base != 0 && base < 2) || base > 36) {
|
||||
@@ -69,16 +71,16 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
machine_int_t int_val = 0;
|
||||
const char *restrict str_val_start = str;
|
||||
for (; str < top; str++) {
|
||||
machine_int_t old_val = int_val;
|
||||
// get next digit as a value
|
||||
int 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 +89,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 +105,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,14 +124,19 @@ 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 = str_val_start;
|
||||
ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
|
||||
str = 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)
|
||||
@@ -131,7 +144,7 @@ overflow:
|
||||
#define PARSE_DEC_IN_EXP (3)
|
||||
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
const char *top = str + len;
|
||||
mp_float_t dec_val = 0;
|
||||
bool dec_neg = false;
|
||||
|
||||
60
py/pfenv.c
60
py/pfenv.c
@@ -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) {
|
||||
@@ -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;
|
||||
|
||||
@@ -230,6 +238,9 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
|
||||
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';
|
||||
|
||||
@@ -45,7 +45,7 @@ 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_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)"
|
||||
|
||||
14
py/qstr.c
14
py/qstr.c
@@ -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,7 +130,7 @@ 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);
|
||||
|
||||
@@ -152,7 +152,7 @@ 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);
|
||||
byte *q_ptr = m_new(byte, 4 + len + 1);
|
||||
@@ -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,7 +176,7 @@ 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);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// See qstrraw.h for a list of qstr's that are available as constants.
|
||||
// See qstrdefs.h for a list of qstr's that are available as constants.
|
||||
// Reference them as MP_QSTR_xxxx.
|
||||
//
|
||||
// Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static("xxx")
|
||||
@@ -46,12 +46,11 @@ typedef machine_uint_t qstr;
|
||||
void qstr_init(void);
|
||||
|
||||
machine_uint_t qstr_compute_hash(const byte *data, uint len);
|
||||
qstr qstr_find_strn(const byte *str, uint str_len); // returns MP_QSTR_NULL if not found
|
||||
qstr qstr_find_strn(const char *str, uint str_len); // returns MP_QSTR_NULL if not found
|
||||
|
||||
qstr qstr_from_str(const char *str);
|
||||
qstr qstr_from_strn(const char *str, uint len);
|
||||
//qstr qstr_from_str_static(const char *str);
|
||||
qstr qstr_from_strn_take(char *str, uint alloc_len, uint len);
|
||||
//qstr qstr_from_strn_copy(const char *str, int len);
|
||||
|
||||
byte* qstr_build_start(uint len, byte **q_ptr);
|
||||
|
||||
@@ -34,6 +34,7 @@ Q(__class__)
|
||||
Q(__doc__)
|
||||
Q(__import__)
|
||||
Q(__init__)
|
||||
Q(__new__)
|
||||
Q(__locals__)
|
||||
Q(__main__)
|
||||
Q(__module__)
|
||||
@@ -59,6 +60,7 @@ Q(__str__)
|
||||
Q(__getattr__)
|
||||
Q(__del__)
|
||||
Q(__call__)
|
||||
Q(__lt__)
|
||||
|
||||
Q(micropython)
|
||||
Q(bytecode)
|
||||
@@ -101,6 +103,7 @@ Q(OverflowError)
|
||||
Q(RuntimeError)
|
||||
Q(SyntaxError)
|
||||
Q(SystemError)
|
||||
Q(SystemExit)
|
||||
Q(TypeError)
|
||||
Q(UnboundLocalError)
|
||||
Q(ValueError)
|
||||
@@ -124,7 +127,7 @@ Q(bool)
|
||||
Q(bytearray)
|
||||
Q(bytes)
|
||||
Q(callable)
|
||||
#if MICROPY_ENABLE_MOD_STRUCT
|
||||
#if MICROPY_PY_STRUCT
|
||||
Q(calcsize)
|
||||
#endif
|
||||
Q(chr)
|
||||
@@ -236,12 +239,19 @@ Q(find)
|
||||
Q(rfind)
|
||||
Q(rindex)
|
||||
Q(split)
|
||||
Q(rsplit)
|
||||
Q(startswith)
|
||||
Q(endswith)
|
||||
Q(replace)
|
||||
Q(partition)
|
||||
Q(rpartition)
|
||||
Q(lower)
|
||||
Q(upper)
|
||||
Q(isspace)
|
||||
Q(isalpha)
|
||||
Q(isdigit)
|
||||
Q(isupper)
|
||||
Q(islower)
|
||||
Q(iterable)
|
||||
Q(start)
|
||||
|
||||
@@ -254,11 +264,11 @@ Q(iterator)
|
||||
Q(module)
|
||||
Q(slice)
|
||||
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
Q(frozenset)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_MOD_MATH || MICROPY_ENABLE_MOD_CMATH
|
||||
#if MICROPY_PY_MATH || MICROPY_PY_CMATH
|
||||
Q(math)
|
||||
Q(e)
|
||||
Q(pi)
|
||||
@@ -302,7 +312,7 @@ Q(gamma)
|
||||
Q(lgamma)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_MOD_CMATH
|
||||
#if MICROPY_PY_CMATH
|
||||
Q(cmath)
|
||||
Q(phase)
|
||||
Q(polar)
|
||||
@@ -328,12 +338,15 @@ Q(decode)
|
||||
Q(utf-8)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
Q(argv)
|
||||
Q(byteorder)
|
||||
Q(big)
|
||||
Q(exit)
|
||||
Q(little)
|
||||
#ifdef MICROPY_PY_SYS_PLATFORM
|
||||
Q(platform)
|
||||
#endif
|
||||
Q(stdin)
|
||||
Q(stdout)
|
||||
Q(stderr)
|
||||
@@ -341,30 +354,32 @@ Q(version)
|
||||
Q(version_info)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_MOD_STRUCT
|
||||
#if MICROPY_PY_STRUCT
|
||||
Q(struct)
|
||||
Q(pack)
|
||||
Q(unpack)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_MOD_IO
|
||||
Q(io)
|
||||
#if MICROPY_PY_IO
|
||||
Q(_io)
|
||||
Q(readall)
|
||||
Q(readline)
|
||||
Q(readlines)
|
||||
Q(FileIO)
|
||||
Q(TextIOWrapper)
|
||||
Q(StringIO)
|
||||
Q(BytesIO)
|
||||
Q(getvalue)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_MOD_GC
|
||||
#if MICROPY_PY_GC
|
||||
Q(gc)
|
||||
Q(collect)
|
||||
Q(disable)
|
||||
Q(enable)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_PROPERTY
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
Q(property)
|
||||
Q(getter)
|
||||
Q(setter)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "mpconfig.h"
|
||||
#include "repl.h"
|
||||
|
||||
#if MICROPY_ENABLE_REPL_HELPERS
|
||||
#if MICROPY_HELPER_REPL
|
||||
|
||||
bool str_startswith_word(const char *str, const char *head) {
|
||||
int i;
|
||||
@@ -107,4 +107,4 @@ bool mp_repl_continue_with_input(const char *input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_REPL_HELPERS
|
||||
#endif // MICROPY_HELPER_REPL
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if MICROPY_ENABLE_REPL_HELPERS
|
||||
#if MICROPY_HELPER_REPL
|
||||
bool mp_repl_continue_with_input(const char *input);
|
||||
#endif
|
||||
|
||||
46
py/runtime.c
46
py/runtime.c
@@ -27,7 +27,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
@@ -45,6 +44,7 @@
|
||||
#include "bc.h"
|
||||
#include "smallint.h"
|
||||
#include "objgenerator.h"
|
||||
#include "lexer.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -69,12 +69,13 @@ const mp_obj_module_t mp_module___main__ = {
|
||||
};
|
||||
|
||||
void mp_init(void) {
|
||||
// call port specific initialization if any
|
||||
// call port specific initialization if any
|
||||
#ifdef MICROPY_PORT_INIT_FUNC
|
||||
MICROPY_PORT_INIT_FUNC;
|
||||
#endif
|
||||
|
||||
mp_emit_glue_init();
|
||||
// optimization disabled by default
|
||||
mp_optimise_value = 0;
|
||||
|
||||
// init global module stuff
|
||||
mp_module_init();
|
||||
@@ -90,7 +91,6 @@ void mp_init(void) {
|
||||
void mp_deinit(void) {
|
||||
//mp_obj_dict_free(&dict_main);
|
||||
mp_module_deinit();
|
||||
mp_emit_glue_deinit();
|
||||
|
||||
// call port specific deinitialization if any
|
||||
#ifdef MICROPY_PORT_INIT_FUNC
|
||||
@@ -98,6 +98,13 @@ void mp_deinit(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_obj_t mp_load_const_int(qstr qstr) {
|
||||
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
|
||||
uint len;
|
||||
const byte* data = qstr_data(qstr, &len);
|
||||
return mp_parse_num_integer((const char*)data, len, 0);
|
||||
}
|
||||
|
||||
mp_obj_t mp_load_const_dec(qstr qstr) {
|
||||
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
|
||||
uint len;
|
||||
@@ -200,7 +207,7 @@ mp_obj_t mp_unary_op(int op, 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(op, arg);
|
||||
if (result != MP_OBJ_NOT_SUPPORTED) {
|
||||
if (result != MP_OBJ_NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -346,7 +353,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val);
|
||||
break;
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case MP_BINARY_OP_TRUE_DIVIDE:
|
||||
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
|
||||
if (rhs_val == 0) {
|
||||
@@ -364,7 +371,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
case MP_BINARY_OP_POWER:
|
||||
case MP_BINARY_OP_INPLACE_POWER:
|
||||
if (rhs_val < 0) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
lhs = mp_obj_new_float(lhs_val);
|
||||
goto generic_binary_op;
|
||||
#else
|
||||
@@ -406,12 +413,12 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
goto unsupported_op;
|
||||
}
|
||||
// TODO: We just should make mp_obj_new_int() inline and use that
|
||||
if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
|
||||
if (MP_SMALL_INT_FITS(lhs_val)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(lhs_val);
|
||||
} else {
|
||||
return mp_obj_new_int(lhs_val);
|
||||
}
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {
|
||||
mp_obj_t res = mp_obj_float_binary_op(op, lhs_val, rhs);
|
||||
if (res == MP_OBJ_NULL) {
|
||||
@@ -439,7 +446,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(rhs);
|
||||
if (type->binary_op != NULL) {
|
||||
mp_obj_t res = type->binary_op(op, rhs, lhs);
|
||||
if (res != MP_OBJ_NOT_SUPPORTED) {
|
||||
if (res != MP_OBJ_NULL) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -467,7 +474,7 @@ generic_binary_op:
|
||||
type = mp_obj_get_type(lhs);
|
||||
if (type->binary_op != NULL) {
|
||||
mp_obj_t result = type->binary_op(op, lhs, rhs);
|
||||
if (result != MP_OBJ_NOT_SUPPORTED) {
|
||||
if (result != MP_OBJ_NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -518,10 +525,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, uint n_args, uint n_kw, const mp
|
||||
|
||||
// do the call
|
||||
if (type->call != NULL) {
|
||||
mp_obj_t res = type->call(fun_in, n_args, n_kw, args);
|
||||
if (res != NULL) {
|
||||
return res;
|
||||
}
|
||||
return type->call(fun_in, n_args, n_kw, args);
|
||||
}
|
||||
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in)));
|
||||
@@ -832,7 +836,7 @@ void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
|
||||
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
// check if the methods are functions, static or class methods
|
||||
// see http://docs.python.org/3.3/howto/descriptor.html
|
||||
// see http://docs.python.org/3/howto/descriptor.html
|
||||
if (MP_OBJ_IS_TYPE(elem->value, &mp_type_staticmethod)) {
|
||||
// return just the function
|
||||
dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
|
||||
@@ -1145,10 +1149,14 @@ void *m_malloc_fail(int num_bytes) {
|
||||
nlr_raise((mp_obj_t)&mp_const_MemoryError_obj);
|
||||
}
|
||||
|
||||
NORETURN void mp_not_implemented(const char *msg) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, msg));
|
||||
}
|
||||
|
||||
// these must correspond to the respective enum
|
||||
void *const mp_fun_table[MP_F_NUMBER_OF] = {
|
||||
mp_load_const_int,
|
||||
mp_load_const_dec,
|
||||
mp_obj_new_int_from_qstr,
|
||||
mp_load_const_str,
|
||||
mp_load_name,
|
||||
mp_load_global,
|
||||
@@ -1166,8 +1174,10 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
|
||||
mp_obj_list_append,
|
||||
mp_obj_new_dict,
|
||||
mp_obj_dict_store,
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
mp_obj_new_set,
|
||||
mp_obj_set_store,
|
||||
#endif
|
||||
mp_make_function_from_raw_code,
|
||||
mp_call_function_n_kw_for_native,
|
||||
mp_call_method_n_kw,
|
||||
@@ -1176,7 +1186,9 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
|
||||
mp_import_name,
|
||||
mp_import_from,
|
||||
mp_import_all,
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
mp_obj_new_slice,
|
||||
#endif
|
||||
mp_unpack_sequence,
|
||||
mp_unpack_ex,
|
||||
};
|
||||
|
||||
@@ -75,6 +75,7 @@ void mp_delete_global(qstr qstr);
|
||||
mp_obj_t mp_unary_op(int op, mp_obj_t arg);
|
||||
mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
|
||||
|
||||
mp_obj_t mp_load_const_int(qstr qstr);
|
||||
mp_obj_t mp_load_const_dec(qstr qstr);
|
||||
mp_obj_t mp_load_const_str(qstr qstr);
|
||||
mp_obj_t mp_load_const_bytes(qstr qstr);
|
||||
@@ -111,6 +112,9 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);
|
||||
mp_obj_t mp_import_from(mp_obj_t module, qstr name);
|
||||
void mp_import_all(mp_obj_t module);
|
||||
|
||||
// Raise NotImplementedError with given message
|
||||
NORETURN void mp_not_implemented(const char *msg);
|
||||
|
||||
extern struct _mp_obj_list_t mp_sys_path_obj;
|
||||
extern struct _mp_obj_list_t mp_sys_argv_obj;
|
||||
#define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)
|
||||
|
||||
@@ -96,8 +96,8 @@ typedef enum {
|
||||
} mp_binary_op_t;
|
||||
|
||||
typedef enum {
|
||||
MP_F_LOAD_CONST_DEC = 0,
|
||||
MP_F_LOAD_CONST_INT,
|
||||
MP_F_LOAD_CONST_INT = 0,
|
||||
MP_F_LOAD_CONST_DEC,
|
||||
MP_F_LOAD_CONST_STR,
|
||||
MP_F_LOAD_NAME,
|
||||
MP_F_LOAD_GLOBAL,
|
||||
@@ -115,8 +115,10 @@ typedef enum {
|
||||
MP_F_LIST_APPEND,
|
||||
MP_F_BUILD_MAP,
|
||||
MP_F_STORE_MAP,
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
MP_F_BUILD_SET,
|
||||
MP_F_STORE_SET,
|
||||
#endif
|
||||
MP_F_MAKE_FUNCTION_FROM_RAW_CODE,
|
||||
MP_F_CALL_FUNCTION_N_KW_FOR_NATIVE,
|
||||
MP_F_CALL_METHOD_N_KW,
|
||||
@@ -125,7 +127,9 @@ typedef enum {
|
||||
MP_F_IMPORT_NAME,
|
||||
MP_F_IMPORT_FROM,
|
||||
MP_F_IMPORT_ALL,
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
MP_F_NEW_SLICE,
|
||||
#endif
|
||||
MP_F_UNPACK_SEQUENCE,
|
||||
MP_F_UNPACK_EX,
|
||||
MP_F_NUMBER_OF,
|
||||
|
||||
@@ -71,7 +71,7 @@ scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint
|
||||
}
|
||||
scope->raw_code = mp_emit_glue_new_raw_code();
|
||||
scope->emit_options = emit_options;
|
||||
scope->id_info_alloc = MP_ALLOC_SCOPE_ID_INIT;
|
||||
scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT;
|
||||
scope->id_info = m_new(id_info_t, scope->id_info_alloc);
|
||||
|
||||
return scope;
|
||||
@@ -92,8 +92,8 @@ id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added) {
|
||||
|
||||
// make sure we have enough memory
|
||||
if (scope->id_info_len >= scope->id_info_alloc) {
|
||||
scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MP_ALLOC_SCOPE_ID_INC);
|
||||
scope->id_info_alloc += MP_ALLOC_SCOPE_ID_INC;
|
||||
scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC);
|
||||
scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC;
|
||||
}
|
||||
|
||||
// add new id to end of array of all ids; this seems to match CPython
|
||||
|
||||
@@ -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
|
||||
@@ -50,11 +51,22 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void
|
||||
}
|
||||
}
|
||||
|
||||
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
|
||||
machine_int_t start, stop, step;
|
||||
mp_obj_slice_get(slice, &start, &stop, &step);
|
||||
if (step != 1) {
|
||||
return false;
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
|
||||
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) {
|
||||
mp_obj_t ostart, ostop, ostep;
|
||||
machine_int_t start, stop;
|
||||
mp_obj_slice_get(slice, &ostart, &ostop, &ostep);
|
||||
|
||||
if (ostart == mp_const_none) {
|
||||
start = 0;
|
||||
} else {
|
||||
start = MP_OBJ_SMALL_INT_VALUE(ostart);
|
||||
}
|
||||
if (ostop == mp_const_none) {
|
||||
stop = len;
|
||||
} else {
|
||||
stop = MP_OBJ_SMALL_INT_VALUE(ostop);
|
||||
}
|
||||
|
||||
// Unlike subscription, out-of-bounds slice indexes are never error
|
||||
@@ -66,20 +78,51 @@ bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_u
|
||||
} else if (start > len) {
|
||||
start = len;
|
||||
}
|
||||
if (stop <= 0) {
|
||||
if (stop < 0) {
|
||||
stop = len + stop;
|
||||
// CPython returns empty sequence in such case
|
||||
if (stop < 0) {
|
||||
stop = start;
|
||||
}
|
||||
} else if (stop > len) {
|
||||
stop = len;
|
||||
}
|
||||
*begin = start;
|
||||
*end = stop;
|
||||
|
||||
// CPython returns empty sequence in such case, or point for assignment is at start
|
||||
if (start > stop) {
|
||||
stop = start;
|
||||
}
|
||||
|
||||
indexes->start = start;
|
||||
indexes->stop = stop;
|
||||
|
||||
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
|
||||
indexes->step = MP_OBJ_SMALL_INT_VALUE(ostep);
|
||||
return false;
|
||||
}
|
||||
indexes->step = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mp_obj_t mp_seq_extract_slice(uint len, const mp_obj_t *seq, mp_bound_slice_t *indexes) {
|
||||
machine_int_t start = indexes->start, stop = indexes->stop;
|
||||
machine_int_t step = indexes->step;
|
||||
|
||||
mp_obj_t res = mp_obj_new_list(0, NULL);
|
||||
|
||||
if (step < 0) {
|
||||
stop--;
|
||||
while (start <= stop) {
|
||||
mp_obj_list_append(res, seq[stop]);
|
||||
stop += step;
|
||||
}
|
||||
} else {
|
||||
while (start < stop) {
|
||||
mp_obj_list_append(res, seq[start]);
|
||||
start += step;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Special-case comparison function for sequences of bytes
|
||||
// Don't pass MP_BINARY_OP_NOT_EQUAL here
|
||||
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
|
||||
@@ -99,6 +142,10 @@ bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, u
|
||||
}
|
||||
uint min_len = len1 < len2 ? len1 : len2;
|
||||
int res = memcmp(data1, data2, min_len);
|
||||
if (op == MP_BINARY_OP_EQUAL) {
|
||||
// If we are checking for equality, here're the answer
|
||||
return res == 0;
|
||||
}
|
||||
if (res < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
20
py/showbc.c
20
py/showbc.c
@@ -56,7 +56,7 @@
|
||||
|
||||
void mp_bytecode_print2(const byte *ip, int len);
|
||||
|
||||
void mp_bytecode_print(const byte *ip, int len) {
|
||||
void mp_bytecode_print(const void *descr, const byte *ip, int len) {
|
||||
const byte *ip_start = ip;
|
||||
|
||||
// get code info size
|
||||
@@ -64,6 +64,11 @@ void mp_bytecode_print(const byte *ip, int len) {
|
||||
const byte *code_info = ip;
|
||||
ip += code_info_size;
|
||||
|
||||
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
|
||||
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
|
||||
printf("File %s, code block '%s' (descriptor: %p, bytecode @%p %d bytes)\n",
|
||||
qstr_str(source_file), qstr_str(block_name), descr, code_info, len);
|
||||
|
||||
// bytecode prelude: state size and exception stack size; 16 bit uints
|
||||
{
|
||||
uint n_state = ip[0] | (ip[1] << 8);
|
||||
@@ -87,9 +92,6 @@ void mp_bytecode_print(const byte *ip, int len) {
|
||||
|
||||
// print out line number info
|
||||
{
|
||||
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
|
||||
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
|
||||
printf("File %s, block '%s'\n", qstr_str(source_file), qstr_str(block_name));
|
||||
machine_int_t bc = (code_info + code_info_size) - ip;
|
||||
machine_uint_t source_line = 1;
|
||||
printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
|
||||
@@ -419,7 +421,7 @@ void mp_bytecode_print2(const byte *ip, int len) {
|
||||
printf("SET_ADD " UINT_FMT, unum);
|
||||
break;
|
||||
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
case MP_BC_BUILD_SLICE:
|
||||
DECODE_UINT;
|
||||
printf("BUILD_SLICE " UINT_FMT, unum);
|
||||
@@ -433,25 +435,25 @@ void mp_bytecode_print2(const byte *ip, int len) {
|
||||
|
||||
case MP_BC_MAKE_FUNCTION:
|
||||
DECODE_PTR;
|
||||
printf("MAKE_FUNCTION " UINT_FMT, unum);
|
||||
printf("MAKE_FUNCTION %p", (void*)unum);
|
||||
break;
|
||||
|
||||
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
||||
DECODE_PTR;
|
||||
printf("MAKE_FUNCTION_DEFARGS " UINT_FMT, unum);
|
||||
printf("MAKE_FUNCTION_DEFARGS %p", (void*)unum);
|
||||
break;
|
||||
|
||||
case MP_BC_MAKE_CLOSURE: {
|
||||
DECODE_PTR;
|
||||
machine_uint_t n_closed_over = *ip++;
|
||||
printf("MAKE_CLOSURE " UINT_FMT " " UINT_FMT, unum, n_closed_over);
|
||||
printf("MAKE_CLOSURE %p " UINT_FMT, (void*)unum, n_closed_over);
|
||||
break;
|
||||
}
|
||||
|
||||
case MP_BC_MAKE_CLOSURE_DEFARGS: {
|
||||
DECODE_PTR;
|
||||
machine_uint_t n_closed_over = *ip++;
|
||||
printf("MAKE_CLOSURE_DEFARGS " UINT_FMT " " UINT_FMT, unum, n_closed_over);
|
||||
printf("MAKE_CLOSURE_DEFARGS %p " UINT_FMT, (void*)unum, n_closed_over);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mpconfig.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "smallint.h"
|
||||
|
||||
bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) {
|
||||
// Check for multiply overflow; see CERT INT32-C
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
|
||||
// Functions for small integer arithmetic
|
||||
|
||||
// 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_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
|
||||
|
||||
bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y);
|
||||
machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor);
|
||||
machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom);
|
||||
|
||||
10
py/stream.c
10
py/stream.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
|
||||
@@ -31,6 +32,7 @@
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objstr.h"
|
||||
#include "stream.h"
|
||||
#if MICROPY_STREAMS_NON_BLOCK
|
||||
#include <errno.h>
|
||||
@@ -52,6 +54,8 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
|
||||
#define is_nonblocking_error(errno) (0)
|
||||
#endif
|
||||
|
||||
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_bytes) ? &mp_type_bytes : &mp_type_str)
|
||||
|
||||
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
|
||||
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
|
||||
@@ -77,7 +81,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
|
||||
} else {
|
||||
mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size
|
||||
mp_obj_t s = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), buf, out_sz); // will reallocate to use exact size
|
||||
m_free(buf, sz);
|
||||
return s;
|
||||
}
|
||||
@@ -154,7 +158,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, total_size, false);
|
||||
mp_obj_t s = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, total_size);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
@@ -203,7 +207,7 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
}
|
||||
// TODO need a string creation API that doesn't copy the given data
|
||||
mp_obj_t ret = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
|
||||
mp_obj_t ret = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, vstr->len);
|
||||
vstr_free(vstr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
425
py/vm.c
425
py/vm.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
|
||||
@@ -39,13 +40,6 @@
|
||||
#include "bc.h"
|
||||
#include "objgenerator.h"
|
||||
|
||||
// With these macros you can tune the maximum number of state slots
|
||||
// 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)
|
||||
#define VM_MAX_EXC_STATE_ON_STACK (4)
|
||||
|
||||
#define DETECT_VM_STACK_OVERFLOW (0)
|
||||
#if 0
|
||||
#define TRACE(ip) mp_bytecode_print2(ip, 1);
|
||||
#else
|
||||
@@ -75,12 +69,10 @@ typedef enum {
|
||||
} while (0)
|
||||
#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)
|
||||
#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)
|
||||
#define DECODE_QSTR do { \
|
||||
qst = 0; \
|
||||
#define DECODE_QSTR qstr qst = 0; \
|
||||
do { \
|
||||
qst = (qst << 7) + (*ip & 0x7f); \
|
||||
} while ((*ip++ & 0x80) != 0); \
|
||||
} while (0)
|
||||
} while ((*ip++ & 0x80) != 0)
|
||||
#define DECODE_PTR do { \
|
||||
ip = (byte*)(((machine_uint_t)ip + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1))); /* align ip */ \
|
||||
unum = *(machine_uint_t*)ip; \
|
||||
@@ -94,7 +86,7 @@ typedef enum {
|
||||
#define PUSH_EXC_BLOCK() \
|
||||
DECODE_ULABEL; /* except labels are always forward */ \
|
||||
++exc_sp; \
|
||||
exc_sp->opcode = *save_ip; \
|
||||
exc_sp->opcode = *code_state->ip; \
|
||||
exc_sp->handler = ip + unum; \
|
||||
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
|
||||
exc_sp->prev_exc = MP_OBJ_NULL; \
|
||||
@@ -104,128 +96,18 @@ typedef enum {
|
||||
currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \
|
||||
exc_sp--; /* pop back to previous exception handler */
|
||||
|
||||
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) {
|
||||
const byte *ip = code;
|
||||
|
||||
// get code info size, and skip line number table
|
||||
machine_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
|
||||
machine_uint_t n_state = ip[0] | (ip[1] << 8);
|
||||
machine_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
|
||||
ip += 4;
|
||||
|
||||
// allocate state for locals and stack
|
||||
mp_obj_t temp_state[VM_MAX_STATE_ON_STACK];
|
||||
mp_obj_t *state = &temp_state[0];
|
||||
#if DETECT_VM_STACK_OVERFLOW
|
||||
n_state += 1;
|
||||
#endif
|
||||
if (n_state > VM_MAX_STATE_ON_STACK) {
|
||||
state = m_new(mp_obj_t, n_state);
|
||||
}
|
||||
mp_obj_t *sp = &state[0] - 1;
|
||||
|
||||
// allocate state for exceptions
|
||||
mp_exc_stack_t exc_state[VM_MAX_EXC_STATE_ON_STACK];
|
||||
mp_exc_stack_t *exc_stack = &exc_state[0];
|
||||
if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
|
||||
exc_stack = m_new(mp_exc_stack_t, n_exc_stack);
|
||||
}
|
||||
mp_exc_stack_t *exc_sp = &exc_stack[0] - 1;
|
||||
|
||||
// init args
|
||||
for (uint i = 0; i < n_args; i++) {
|
||||
state[n_state - 1 - i] = args[i];
|
||||
}
|
||||
for (uint i = 0; i < n_args2; i++) {
|
||||
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++) {
|
||||
state[i] = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
for (uint n_local = *ip++; n_local > 0; n_local--) {
|
||||
uint local_num = *ip++;
|
||||
state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]);
|
||||
}
|
||||
|
||||
// execute the byte code
|
||||
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL);
|
||||
|
||||
#if DETECT_VM_STACK_OVERFLOW
|
||||
// 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 && n_args == 0 && n_args2 == 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 - n_args - n_args2; i++) {
|
||||
if (state[i] == MP_OBJ_NULL) {
|
||||
overflow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overflow) {
|
||||
printf("VM stack overflow state=%p n_state+1=%u\n", state, n_state);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_vm_return_kind_t ret_kind;
|
||||
switch (vm_return_kind) {
|
||||
case MP_VM_RETURN_NORMAL:
|
||||
// return value is in *sp
|
||||
*ret = *sp;
|
||||
ret_kind = MP_VM_RETURN_NORMAL;
|
||||
break;
|
||||
|
||||
case MP_VM_RETURN_EXCEPTION:
|
||||
// return value is in state[n_state - 1]
|
||||
*ret = state[n_state - 1];
|
||||
ret_kind = MP_VM_RETURN_EXCEPTION;
|
||||
break;
|
||||
|
||||
case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
|
||||
default:
|
||||
assert(0);
|
||||
*ret = mp_const_none;
|
||||
ret_kind = MP_VM_RETURN_NORMAL;
|
||||
}
|
||||
|
||||
// free the state if it was allocated on the heap
|
||||
if (n_state > VM_MAX_STATE_ON_STACK) {
|
||||
m_free(state, n_state);
|
||||
}
|
||||
|
||||
// free the exception state if it was allocated on the heap
|
||||
if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
|
||||
m_free(exc_stack, n_exc_stack);
|
||||
}
|
||||
|
||||
return ret_kind;
|
||||
}
|
||||
|
||||
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
|
||||
// sp points to bottom of stack which grows up
|
||||
// returns:
|
||||
// MP_VM_RETURN_NORMAL, sp valid, return value in *sp
|
||||
// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
|
||||
// MP_VM_RETURN_EXCEPTION, exception in fastn[0]
|
||||
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) {
|
||||
#if MICROPY_USE_COMPUTED_GOTO
|
||||
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc) {
|
||||
#if MICROPY_OPT_COMPUTED_GOTO
|
||||
#include "vmentrytable.h"
|
||||
#define DISPATCH() do { \
|
||||
TRACE(ip); \
|
||||
save_ip = ip; \
|
||||
code_state->ip = ip; \
|
||||
goto *entry_table[*ip++]; \
|
||||
} while(0)
|
||||
#define ENTRY(op) entry_##op
|
||||
@@ -242,11 +124,13 @@ mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_
|
||||
// loop and the exception handler, leading to very obscure bugs.
|
||||
#define RAISE(o) do { nlr_pop(); nlr.ret_val = o; goto exception_handler; } while(0)
|
||||
|
||||
// Pointers which are constant for particular invocation of mp_execute_bytecode()
|
||||
mp_obj_t *const fastn = &code_state->state[code_state->n_state - 1];
|
||||
mp_exc_stack_t *const exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state);
|
||||
|
||||
// variables that are visible to the exception handler (declared volatile)
|
||||
volatile bool currently_in_except_block = MP_TAGPTR_TAG(*exc_sp_in_out); // 0 or 1, to detect nested exceptions
|
||||
mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(*exc_sp_in_out); // stack grows up, exc_sp points to top of stack
|
||||
const byte *volatile save_ip = *ip_in_out; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
|
||||
mp_obj_t *volatile save_sp = *sp_in_out; // this is so we can access sp in the exception handler when needed
|
||||
volatile bool currently_in_except_block = MP_TAGPTR_TAG(code_state->exc_sp); // 0 or 1, to detect nested exceptions
|
||||
mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack
|
||||
|
||||
// outer exception handling loop
|
||||
for (;;) {
|
||||
@@ -254,11 +138,10 @@ mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_
|
||||
outer_dispatch_loop:
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
// local variables that are not visible to the exception handler
|
||||
const byte *ip = *ip_in_out;
|
||||
mp_obj_t *sp = *sp_in_out;
|
||||
const byte *ip = code_state->ip;
|
||||
mp_obj_t *sp = code_state->sp;
|
||||
machine_uint_t unum;
|
||||
qstr qst;
|
||||
mp_obj_t obj1, obj2;
|
||||
mp_obj_t obj_shared;
|
||||
|
||||
// If we have exception to inject, now that we finish setting up
|
||||
// execution context, raise it. This works as if RAISE_VARARGS
|
||||
@@ -266,20 +149,20 @@ outer_dispatch_loop:
|
||||
// Injecting exc into yield from generator is a special case,
|
||||
// handled by MP_BC_YIELD_FROM itself
|
||||
if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) {
|
||||
obj1 = inject_exc;
|
||||
mp_obj_t exc = inject_exc;
|
||||
inject_exc = MP_OBJ_NULL;
|
||||
obj1 = mp_make_raise_obj(obj1);
|
||||
RAISE(obj1);
|
||||
exc = mp_make_raise_obj(exc);
|
||||
RAISE(exc);
|
||||
}
|
||||
|
||||
// loop to execute byte code
|
||||
for (;;) {
|
||||
dispatch_loop:
|
||||
#if MICROPY_USE_COMPUTED_GOTO
|
||||
#if MICROPY_OPT_COMPUTED_GOTO
|
||||
DISPATCH();
|
||||
#else
|
||||
TRACE(ip);
|
||||
save_ip = ip;
|
||||
code_state->ip = ip;
|
||||
switch (*ip++) {
|
||||
#endif
|
||||
|
||||
@@ -312,88 +195,98 @@ dispatch_loop:
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_CONST_INT):
|
||||
ENTRY(MP_BC_LOAD_CONST_INT): {
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_obj_new_int_from_qstr(qst));
|
||||
PUSH(mp_load_const_int(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_CONST_DEC):
|
||||
ENTRY(MP_BC_LOAD_CONST_DEC): {
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_const_dec(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_CONST_BYTES):
|
||||
ENTRY(MP_BC_LOAD_CONST_BYTES): {
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_const_bytes(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_CONST_STRING):
|
||||
ENTRY(MP_BC_LOAD_CONST_STRING): {
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_const_str(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_NULL):
|
||||
PUSH(MP_OBJ_NULL);
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_0):
|
||||
obj1 = fastn[0];
|
||||
obj_shared = fastn[0];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_1):
|
||||
obj1 = fastn[-1];
|
||||
obj_shared = fastn[-1];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_2):
|
||||
obj1 = fastn[-2];
|
||||
obj_shared = fastn[-2];
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_FAST_N):
|
||||
DECODE_UINT;
|
||||
obj1 = fastn[-unum];
|
||||
obj_shared = fastn[-unum];
|
||||
load_check:
|
||||
if (obj1 == MP_OBJ_NULL) {
|
||||
local_name_error:
|
||||
obj1 = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment");
|
||||
RAISE(obj1);
|
||||
if (obj_shared == MP_OBJ_NULL) {
|
||||
local_name_error: {
|
||||
mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment");
|
||||
RAISE(obj);
|
||||
}
|
||||
}
|
||||
PUSH(obj1);
|
||||
PUSH(obj_shared);
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_LOAD_DEREF):
|
||||
DECODE_UINT;
|
||||
obj1 = mp_obj_cell_get(fastn[-unum]);
|
||||
obj_shared = mp_obj_cell_get(fastn[-unum]);
|
||||
goto load_check;
|
||||
|
||||
ENTRY(MP_BC_LOAD_NAME):
|
||||
ENTRY(MP_BC_LOAD_NAME): {
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_name(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_GLOBAL):
|
||||
ENTRY(MP_BC_LOAD_GLOBAL): {
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_global(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_ATTR):
|
||||
ENTRY(MP_BC_LOAD_ATTR): {
|
||||
DECODE_QSTR;
|
||||
SET_TOP(mp_load_attr(TOP(), qst));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_METHOD):
|
||||
ENTRY(MP_BC_LOAD_METHOD): {
|
||||
DECODE_QSTR;
|
||||
mp_load_method(*sp, qst, sp);
|
||||
sp += 1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_BUILD_CLASS):
|
||||
PUSH(mp_load_build_class());
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_LOAD_SUBSCR):
|
||||
obj1 = POP();
|
||||
SET_TOP(mp_obj_subscr(TOP(), obj1, MP_OBJ_SENTINEL));
|
||||
ENTRY(MP_BC_LOAD_SUBSCR): {
|
||||
mp_obj_t index = POP();
|
||||
SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_STORE_FAST_0):
|
||||
fastn[0] = POP();
|
||||
@@ -417,21 +310,24 @@ dispatch_loop:
|
||||
mp_obj_cell_set(fastn[-unum], POP());
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_STORE_NAME):
|
||||
ENTRY(MP_BC_STORE_NAME): {
|
||||
DECODE_QSTR;
|
||||
mp_store_name(qst, POP());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_STORE_GLOBAL):
|
||||
ENTRY(MP_BC_STORE_GLOBAL): {
|
||||
DECODE_QSTR;
|
||||
mp_store_global(qst, POP());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_STORE_ATTR):
|
||||
ENTRY(MP_BC_STORE_ATTR): {
|
||||
DECODE_QSTR;
|
||||
mp_store_attr(sp[0], qst, sp[-1]);
|
||||
sp -= 2;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_STORE_SUBSCR):
|
||||
mp_obj_subscr(sp[-1], sp[0], sp[-2]);
|
||||
@@ -454,20 +350,23 @@ dispatch_loop:
|
||||
mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL);
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_DELETE_NAME):
|
||||
ENTRY(MP_BC_DELETE_NAME): {
|
||||
DECODE_QSTR;
|
||||
mp_delete_name(qst);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_DELETE_GLOBAL):
|
||||
ENTRY(MP_BC_DELETE_GLOBAL): {
|
||||
DECODE_QSTR;
|
||||
mp_delete_global(qst);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_DUP_TOP):
|
||||
obj1 = TOP();
|
||||
PUSH(obj1);
|
||||
ENTRY(MP_BC_DUP_TOP): {
|
||||
mp_obj_t top = TOP();
|
||||
PUSH(top);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_DUP_TOP_TWO):
|
||||
sp += 2;
|
||||
@@ -479,18 +378,20 @@ dispatch_loop:
|
||||
sp -= 1;
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_ROT_TWO):
|
||||
obj1 = sp[0];
|
||||
ENTRY(MP_BC_ROT_TWO): {
|
||||
mp_obj_t top = sp[0];
|
||||
sp[0] = sp[-1];
|
||||
sp[-1] = obj1;
|
||||
sp[-1] = top;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_ROT_THREE):
|
||||
obj1 = sp[0];
|
||||
ENTRY(MP_BC_ROT_THREE): {
|
||||
mp_obj_t top = sp[0];
|
||||
sp[0] = sp[-1];
|
||||
sp[-1] = sp[-2];
|
||||
sp[-2] = obj1;
|
||||
sp[-2] = top;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_JUMP):
|
||||
DECODE_SLABEL;
|
||||
@@ -529,14 +430,15 @@ dispatch_loop:
|
||||
}
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_SETUP_WITH):
|
||||
obj1 = TOP();
|
||||
SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__));
|
||||
mp_load_method(obj1, MP_QSTR___enter__, sp + 1);
|
||||
obj2 = mp_call_method_n_kw(0, 0, sp + 1);
|
||||
ENTRY(MP_BC_SETUP_WITH): {
|
||||
mp_obj_t obj = TOP();
|
||||
SET_TOP(mp_load_attr(obj, MP_QSTR___exit__));
|
||||
mp_load_method(obj, MP_QSTR___enter__, sp + 1);
|
||||
mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 1);
|
||||
PUSH_EXC_BLOCK();
|
||||
PUSH(obj2);
|
||||
PUSH(ret);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_WITH_CLEANUP): {
|
||||
// Arriving here, there's "exception control block" on top of stack,
|
||||
@@ -546,21 +448,21 @@ dispatch_loop:
|
||||
static const mp_obj_t no_exc[] = {mp_const_none, mp_const_none, mp_const_none};
|
||||
if (TOP() == mp_const_none) {
|
||||
sp--;
|
||||
obj1 = TOP();
|
||||
mp_obj_t obj = TOP();
|
||||
SET_TOP(mp_const_none);
|
||||
obj2 = mp_call_function_n_kw(obj1, 3, 0, no_exc);
|
||||
mp_call_function_n_kw(obj, 3, 0, no_exc);
|
||||
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
|
||||
mp_obj_t cause = POP();
|
||||
switch (MP_OBJ_SMALL_INT_VALUE(cause)) {
|
||||
case UNWIND_RETURN: {
|
||||
mp_obj_t retval = POP();
|
||||
obj2 = mp_call_function_n_kw(TOP(), 3, 0, no_exc);
|
||||
mp_call_function_n_kw(TOP(), 3, 0, no_exc);
|
||||
SET_TOP(retval);
|
||||
PUSH(cause);
|
||||
break;
|
||||
}
|
||||
case UNWIND_JUMP: {
|
||||
obj2 = mp_call_function_n_kw(sp[-2], 3, 0, no_exc);
|
||||
mp_call_function_n_kw(sp[-2], 3, 0, no_exc);
|
||||
// Pop __exit__ boundmethod at sp[-2]
|
||||
sp[-2] = sp[-1];
|
||||
sp[-1] = sp[0];
|
||||
@@ -572,14 +474,14 @@ dispatch_loop:
|
||||
}
|
||||
} else if (mp_obj_is_exception_type(TOP())) {
|
||||
mp_obj_t args[3] = {sp[0], sp[-1], sp[-2]};
|
||||
obj2 = mp_call_function_n_kw(sp[-3], 3, 0, args);
|
||||
mp_obj_t ret_value = mp_call_function_n_kw(sp[-3], 3, 0, args);
|
||||
// Pop __exit__ boundmethod at sp[-3]
|
||||
// TODO: Once semantics is proven, optimize for case when obj2 == True
|
||||
// TODO: Once semantics is proven, optimize for case when ret_value == True
|
||||
sp[-3] = sp[-2];
|
||||
sp[-2] = sp[-1];
|
||||
sp[-1] = sp[0];
|
||||
sp--;
|
||||
if (mp_obj_is_true(obj2)) {
|
||||
if (mp_obj_is_true(ret_value)) {
|
||||
// This is what CPython does
|
||||
//PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED));
|
||||
// But what we need to do is - pop exception from value stack...
|
||||
@@ -601,10 +503,10 @@ dispatch_loop:
|
||||
ENTRY(MP_BC_UNWIND_JUMP):
|
||||
DECODE_SLABEL;
|
||||
PUSH((void*)(ip + unum)); // push destination ip for jump
|
||||
PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind
|
||||
PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind (0x80 bit set if we also need to pop stack)
|
||||
unwind_jump:
|
||||
unum = (machine_uint_t)POP(); // get number of exception handlers to unwind
|
||||
while (unum > 0) {
|
||||
while ((unum & 0x7f) > 0) {
|
||||
unum -= 1;
|
||||
assert(exc_sp >= exc_stack);
|
||||
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
|
||||
@@ -621,6 +523,9 @@ unwind_jump:
|
||||
exc_sp--;
|
||||
}
|
||||
ip = (const byte*)POP(); // pop destination ip for jump
|
||||
if (unum != 0) {
|
||||
sp--;
|
||||
}
|
||||
DISPATCH();
|
||||
|
||||
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
|
||||
@@ -660,18 +565,19 @@ unwind_jump:
|
||||
SET_TOP(mp_getiter(TOP()));
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_FOR_ITER):
|
||||
ENTRY(MP_BC_FOR_ITER): {
|
||||
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
|
||||
save_sp = sp;
|
||||
code_state->sp = sp;
|
||||
assert(TOP());
|
||||
obj1 = mp_iternext_allow_raise(TOP());
|
||||
if (obj1 == MP_OBJ_STOP_ITERATION) {
|
||||
mp_obj_t value = mp_iternext_allow_raise(TOP());
|
||||
if (value == MP_OBJ_STOP_ITERATION) {
|
||||
--sp; // pop the exhausted iterator
|
||||
ip += unum; // jump to after for-block
|
||||
} else {
|
||||
PUSH(obj1); // push the next iteration value
|
||||
PUSH(value); // push the next iteration value
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
// matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
|
||||
ENTRY(MP_BC_POP_BLOCK):
|
||||
@@ -705,12 +611,13 @@ unwind_jump:
|
||||
SET_TOP(mp_unary_op(unum, TOP()));
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_BINARY_OP):
|
||||
ENTRY(MP_BC_BINARY_OP): {
|
||||
unum = *ip++;
|
||||
obj2 = POP();
|
||||
obj1 = TOP();
|
||||
SET_TOP(mp_binary_op(unum, obj1, obj2));
|
||||
mp_obj_t rhs = POP();
|
||||
mp_obj_t lhs = TOP();
|
||||
SET_TOP(mp_binary_op(unum, lhs, rhs));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_BUILD_TUPLE):
|
||||
DECODE_UINT;
|
||||
@@ -748,6 +655,7 @@ unwind_jump:
|
||||
sp -= 2;
|
||||
DISPATCH();
|
||||
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
ENTRY(MP_BC_BUILD_SET):
|
||||
DECODE_UINT;
|
||||
sp -= unum - 1;
|
||||
@@ -760,19 +668,20 @@ unwind_jump:
|
||||
mp_obj_set_store(sp[-unum], sp[0]);
|
||||
sp--;
|
||||
DISPATCH();
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
ENTRY(MP_BC_BUILD_SLICE):
|
||||
DECODE_UINT;
|
||||
if (unum == 2) {
|
||||
obj2 = POP();
|
||||
obj1 = TOP();
|
||||
SET_TOP(mp_obj_new_slice(obj1, obj2, NULL));
|
||||
mp_obj_t stop = POP();
|
||||
mp_obj_t start = TOP();
|
||||
SET_TOP(mp_obj_new_slice(start, stop, mp_const_none));
|
||||
} else {
|
||||
obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported");
|
||||
nlr_pop();
|
||||
fastn[0] = obj1;
|
||||
return MP_VM_RETURN_EXCEPTION;
|
||||
mp_obj_t step = POP();
|
||||
mp_obj_t stop = POP();
|
||||
mp_obj_t start = TOP();
|
||||
SET_TOP(mp_obj_new_slice(start, stop, step));
|
||||
}
|
||||
DISPATCH();
|
||||
#endif
|
||||
@@ -794,12 +703,13 @@ unwind_jump:
|
||||
PUSH(mp_make_function_from_raw_code((mp_raw_code_t*)unum, MP_OBJ_NULL, MP_OBJ_NULL));
|
||||
DISPATCH();
|
||||
|
||||
ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS):
|
||||
ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): {
|
||||
DECODE_PTR;
|
||||
// Stack layout: def_tuple def_dict <- TOS
|
||||
obj1 = POP();
|
||||
SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1));
|
||||
mp_obj_t def_dict = POP();
|
||||
SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), def_dict));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_MAKE_CLOSURE): {
|
||||
DECODE_PTR;
|
||||
@@ -874,38 +784,40 @@ unwind_return:
|
||||
exc_sp--;
|
||||
}
|
||||
nlr_pop();
|
||||
*sp_in_out = sp;
|
||||
code_state->sp = sp;
|
||||
assert(exc_sp == exc_stack - 1);
|
||||
return MP_VM_RETURN_NORMAL;
|
||||
|
||||
ENTRY(MP_BC_RAISE_VARARGS):
|
||||
ENTRY(MP_BC_RAISE_VARARGS): {
|
||||
unum = *ip++;
|
||||
mp_obj_t obj;
|
||||
assert(unum <= 1);
|
||||
if (unum == 0) {
|
||||
// search for the inner-most previous exception, to reraise it
|
||||
obj1 = MP_OBJ_NULL;
|
||||
obj = MP_OBJ_NULL;
|
||||
for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) {
|
||||
if (e->prev_exc != MP_OBJ_NULL) {
|
||||
obj1 = e->prev_exc;
|
||||
obj = e->prev_exc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obj1 == MP_OBJ_NULL) {
|
||||
obj1 = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise");
|
||||
RAISE(obj1);
|
||||
if (obj == MP_OBJ_NULL) {
|
||||
obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise");
|
||||
RAISE(obj);
|
||||
}
|
||||
} else {
|
||||
obj1 = POP();
|
||||
obj = POP();
|
||||
}
|
||||
obj1 = mp_make_raise_obj(obj1);
|
||||
RAISE(obj1);
|
||||
obj = mp_make_raise_obj(obj);
|
||||
RAISE(obj);
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_YIELD_VALUE):
|
||||
yield:
|
||||
nlr_pop();
|
||||
*ip_in_out = ip;
|
||||
*sp_in_out = sp;
|
||||
*exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
|
||||
code_state->ip = ip;
|
||||
code_state->sp = sp;
|
||||
code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
|
||||
return MP_VM_RETURN_YIELD;
|
||||
|
||||
ENTRY(MP_BC_YIELD_FROM): {
|
||||
@@ -913,30 +825,31 @@ yield:
|
||||
#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type)
|
||||
#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { RAISE(t); }
|
||||
mp_vm_return_kind_t ret_kind;
|
||||
obj1 = POP();
|
||||
mp_obj_t send_value = POP();
|
||||
mp_obj_t t_exc = MP_OBJ_NULL;
|
||||
mp_obj_t ret_value;
|
||||
if (inject_exc != MP_OBJ_NULL) {
|
||||
t_exc = inject_exc;
|
||||
inject_exc = MP_OBJ_NULL;
|
||||
ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &obj2);
|
||||
ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &ret_value);
|
||||
} else {
|
||||
ret_kind = mp_resume(TOP(), obj1, MP_OBJ_NULL, &obj2);
|
||||
ret_kind = mp_resume(TOP(), send_value, MP_OBJ_NULL, &ret_value);
|
||||
}
|
||||
|
||||
if (ret_kind == MP_VM_RETURN_YIELD) {
|
||||
ip--;
|
||||
PUSH(obj2);
|
||||
PUSH(ret_value);
|
||||
goto yield;
|
||||
}
|
||||
if (ret_kind == MP_VM_RETURN_NORMAL) {
|
||||
// Pop exhausted gen
|
||||
sp--;
|
||||
if (obj2 == MP_OBJ_NULL) {
|
||||
if (ret_value == MP_OBJ_NULL) {
|
||||
// Optimize StopIteration
|
||||
// TODO: get StopIteration's value
|
||||
PUSH(mp_const_none);
|
||||
} else {
|
||||
PUSH(obj2);
|
||||
PUSH(ret_value);
|
||||
}
|
||||
|
||||
// If we injected GeneratorExit downstream, then even
|
||||
@@ -947,41 +860,44 @@ yield:
|
||||
if (ret_kind == MP_VM_RETURN_EXCEPTION) {
|
||||
// Pop exhausted gen
|
||||
sp--;
|
||||
if (EXC_MATCH(obj2, &mp_type_StopIteration)) {
|
||||
PUSH(mp_obj_exception_get_value(obj2));
|
||||
if (EXC_MATCH(ret_value, &mp_type_StopIteration)) {
|
||||
PUSH(mp_obj_exception_get_value(ret_value));
|
||||
// If we injected GeneratorExit downstream, then even
|
||||
// if it was swallowed, we re-raise GeneratorExit
|
||||
GENERATOR_EXIT_IF_NEEDED(t_exc);
|
||||
DISPATCH();
|
||||
} else {
|
||||
RAISE(obj2);
|
||||
RAISE(ret_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_IMPORT_NAME):
|
||||
ENTRY(MP_BC_IMPORT_NAME): {
|
||||
DECODE_QSTR;
|
||||
obj1 = POP();
|
||||
SET_TOP(mp_import_name(qst, obj1, TOP()));
|
||||
mp_obj_t obj = POP();
|
||||
SET_TOP(mp_import_name(qst, obj, TOP()));
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_IMPORT_FROM):
|
||||
ENTRY(MP_BC_IMPORT_FROM): {
|
||||
DECODE_QSTR;
|
||||
obj1 = mp_import_from(TOP(), qst);
|
||||
PUSH(obj1);
|
||||
mp_obj_t obj = mp_import_from(TOP(), qst);
|
||||
PUSH(obj);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_IMPORT_STAR):
|
||||
mp_import_all(POP());
|
||||
DISPATCH();
|
||||
|
||||
ENTRY_DEFAULT:
|
||||
obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
|
||||
ENTRY_DEFAULT: {
|
||||
mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
|
||||
nlr_pop();
|
||||
fastn[0] = obj1;
|
||||
fastn[0] = obj;
|
||||
return MP_VM_RETURN_EXCEPTION;
|
||||
}
|
||||
|
||||
#if !MICROPY_USE_COMPUTED_GOTO
|
||||
#if !MICROPY_OPT_COMPUTED_GOTO
|
||||
} // switch
|
||||
#endif
|
||||
} // for loop
|
||||
@@ -991,12 +907,12 @@ exception_handler:
|
||||
// exception occurred
|
||||
|
||||
// check if it's a StopIteration within a for block
|
||||
if (*save_ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
|
||||
const byte *ip = save_ip + 1;
|
||||
if (*code_state->ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
|
||||
const byte *ip = code_state->ip + 1;
|
||||
machine_uint_t unum;
|
||||
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
|
||||
*ip_in_out = ip + unum; // jump to after for-block
|
||||
*sp_in_out = save_sp - 1; // pop the exhausted iterator
|
||||
code_state->ip = ip + unum; // jump to after for-block
|
||||
code_state->sp -= 1; // pop the exhausted iterator
|
||||
goto outer_dispatch_loop; // continue with dispatch loop
|
||||
}
|
||||
|
||||
@@ -1005,15 +921,20 @@ exception_handler:
|
||||
// But consider how to handle nested exceptions.
|
||||
// TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj)
|
||||
if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) {
|
||||
const byte *code_info = code_state->code_info;
|
||||
machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24);
|
||||
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
|
||||
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
|
||||
machine_uint_t source_line = 1;
|
||||
machine_uint_t bc = save_ip - code_info - code_info_size;
|
||||
machine_uint_t source_line = 0;
|
||||
machine_uint_t bc = code_state->ip - code_info - code_info_size;
|
||||
//printf("find %lu %d %d\n", bc, code_info[12], code_info[13]);
|
||||
for (const byte* ci = code_info + 12; *ci && bc >= ((*ci) & 31); ci++) {
|
||||
bc -= *ci & 31;
|
||||
source_line += *ci >> 5;
|
||||
const byte* ci = code_info + 12;
|
||||
if (*ci) {
|
||||
source_line = 1;
|
||||
for (; *ci && bc >= ((*ci) & 31); ci++) {
|
||||
bc -= *ci & 31;
|
||||
source_line += *ci >> 5;
|
||||
}
|
||||
}
|
||||
mp_obj_exception_add_traceback(nlr.ret_val, source_file, source_line, block_name);
|
||||
}
|
||||
@@ -1035,7 +956,7 @@ exception_handler:
|
||||
currently_in_except_block = 1;
|
||||
|
||||
// catch exception and pass to byte code
|
||||
*ip_in_out = exc_sp->handler;
|
||||
code_state->ip = exc_sp->handler;
|
||||
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
|
||||
// save this exception in the stack so it can be used in a reraise, if needed
|
||||
exc_sp->prev_exc = nlr.ret_val;
|
||||
@@ -1043,7 +964,7 @@ exception_handler:
|
||||
PUSH(mp_const_none);
|
||||
PUSH(nlr.ret_val);
|
||||
PUSH(mp_obj_get_type(nlr.ret_val));
|
||||
*sp_in_out = sp;
|
||||
code_state->sp = sp;
|
||||
|
||||
} else {
|
||||
// propagate exception to higher level
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Winitializer-overrides"
|
||||
#endif // __clang__
|
||||
|
||||
static void* entry_table[256] = {
|
||||
[0 ... 255] = &&entry_default,
|
||||
[MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE,
|
||||
@@ -110,3 +115,7 @@ static void* entry_table[256] = {
|
||||
[MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM,
|
||||
[MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR,
|
||||
};
|
||||
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __clang__
|
||||
|
||||
23
qemu-arm/README.md
Normal file
23
qemu-arm/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
This is experimental, community-supported port for Cortex-M emulation as
|
||||
provided my QEMU (http://qemu.org).
|
||||
|
||||
The purposes of this port are to enable:
|
||||
|
||||
1. Continuous integration
|
||||
- run tests agains architecture-specific parts of code base
|
||||
2. Experimentation
|
||||
- simulation & prototyping of anything that has architecture-specific
|
||||
code
|
||||
- exploring instruction set in terms of optimising some part of
|
||||
MicroPython or a module
|
||||
3. Streamlined debugging
|
||||
- no need for JTAG or even an MCU chip itself
|
||||
- no need to use OpenOCD or anything else that might slow down the
|
||||
process in terms of plugging things together, pressing buttons, etc.
|
||||
|
||||
This port will only work with with [GCC ARM Embedded](launchpad.net/gcc-arm-embedded)
|
||||
toolchain and not with CodeSourcery toolchain. You will need to modify
|
||||
`LDFLAGS` if you want to use CodeSourcery's version of `arm-none-eabi`.
|
||||
The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while
|
||||
ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be
|
||||
passed to the linker.
|
||||
@@ -2,18 +2,19 @@
|
||||
|
||||
// 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_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_PATH_MAX (512)
|
||||
#define MICROPY_PY_IO (0)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
@@ -29,6 +30,8 @@ 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>
|
||||
|
||||
1
stm/.gitignore
vendored
1
stm/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
build
|
||||
220
stm/Makefile
220
stm/Makefile
@@ -1,220 +0,0 @@
|
||||
include ../py/mkenv.mk
|
||||
|
||||
# qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h
|
||||
|
||||
# include py core make definitions
|
||||
include ../py/py.mk
|
||||
|
||||
CMSIS_DIR=cmsis
|
||||
STMPERIPH_DIR=stmperiph
|
||||
STMUSB_DIR=stmusb
|
||||
STMUSBD_DIR=stmusbd
|
||||
STMUSBH_DIR=stmusbh
|
||||
FATFS_DIR=fatfs
|
||||
CC3K_DIR=cc3k
|
||||
DFU=../tools/dfu.py
|
||||
|
||||
CROSS_COMPILE = arm-none-eabi-
|
||||
|
||||
INC = -I.
|
||||
INC += -I$(PY_SRC)
|
||||
INC += -I$(BUILD)
|
||||
INC += -I$(CMSIS_DIR)
|
||||
INC += -I$(STMPERIPH_DIR)
|
||||
INC += -I$(STMUSB_DIR)
|
||||
INC += -I$(STMUSBD_DIR)
|
||||
INC += -I$(STMUSBH_DIR)
|
||||
INC += -I$(FATFS_DIR)
|
||||
#INC += -I$(CC3K_DIR)
|
||||
|
||||
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)
|
||||
|
||||
BOARD ?= PYBOARD4
|
||||
ifeq ($(wildcard boards/$(BOARD)/.),)
|
||||
$(error Invalid BOARD specified)
|
||||
endif
|
||||
CFLAGS += -Iboards/$(BOARD)
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g -DPENDSV_DEBUG
|
||||
COPT = -O0
|
||||
else
|
||||
COPT += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
LDFLAGS = --nostdlib -T stm32f405.ld -Map=$(@:.elf=.map) --cref
|
||||
LIBS =
|
||||
|
||||
# uncomment this if you want libgcc
|
||||
#LIBS += $(shell $(CC) -print-libgcc-file-name)
|
||||
|
||||
SRC_C = \
|
||||
main.c \
|
||||
printf.c \
|
||||
math.c \
|
||||
system_stm32f4xx.c \
|
||||
stm32fxxx_it.c \
|
||||
string0.c \
|
||||
malloc0.c \
|
||||
systick.c \
|
||||
pendsv.c \
|
||||
gccollect.c \
|
||||
lexerfatfs.c \
|
||||
import.c \
|
||||
pyexec.c \
|
||||
led.c \
|
||||
gpio.c \
|
||||
lcd.c \
|
||||
servo.c \
|
||||
flash.c \
|
||||
storage.c \
|
||||
accel.c \
|
||||
usart.c \
|
||||
usb.c \
|
||||
timer.c \
|
||||
audio.c \
|
||||
sdcard.c \
|
||||
i2c.c \
|
||||
adc.c \
|
||||
rtc.c \
|
||||
file.c \
|
||||
pin.c \
|
||||
pin_named_pins.c \
|
||||
pin_map.c \
|
||||
exti.c \
|
||||
usrsw.c \
|
||||
pybmodule.c \
|
||||
# pybwlan.c \
|
||||
|
||||
SRC_S = \
|
||||
startup_stm32f40xx.s \
|
||||
gchelper.s \
|
||||
|
||||
SRC_STMPERIPH = $(addprefix $(STMPERIPH_DIR)/,\
|
||||
stm_misc.c \
|
||||
stm32f4xx_rcc.c \
|
||||
stm32f4xx_syscfg.c \
|
||||
stm32f4xx_flash.c \
|
||||
stm32f4xx_dma.c \
|
||||
stm32f4xx_gpio.c \
|
||||
stm32f4xx_exti.c \
|
||||
stm32f4xx_tim.c \
|
||||
stm32f4xx_sdio.c \
|
||||
stm32f4xx_pwr.c \
|
||||
stm32f4xx_rtc.c \
|
||||
stm32f4xx_usart.c \
|
||||
stm32f4xx_spi.c \
|
||||
stm32f4xx_dac.c \
|
||||
stm32f4xx_rng.c \
|
||||
stm32f4xx_i2c.c \
|
||||
stm32f4xx_adc.c \
|
||||
stm324x7i_eval.c \
|
||||
stm324x7i_eval_sdio_sd.c \
|
||||
)
|
||||
|
||||
SRC_STMUSB = $(addprefix $(STMUSB_DIR)/,\
|
||||
usb_core.c \
|
||||
usb_bsp.c \
|
||||
usb_dcd.c \
|
||||
usb_dcd_int.c \
|
||||
usb_hcd.c \
|
||||
usb_hcd_int.c \
|
||||
)
|
||||
# usb_otg.c \
|
||||
|
||||
SRC_STMUSBD = $(addprefix $(STMUSBD_DIR)/,\
|
||||
usbd_core.c \
|
||||
usbd_ioreq.c \
|
||||
usbd_req.c \
|
||||
usbd_usr.c \
|
||||
usbd_desc.c \
|
||||
usbd_pyb_core.c \
|
||||
usbd_pyb_core2.c \
|
||||
usbd_cdc_vcp.c \
|
||||
usbd_msc_bot.c \
|
||||
usbd_msc_data.c \
|
||||
usbd_msc_scsi.c \
|
||||
usbd_storage_msd.c \
|
||||
)
|
||||
|
||||
SRC_STMUSBH = $(addprefix $(STMUSBH_DIR)/,\
|
||||
usbh_core.c \
|
||||
usbh_hcs.c \
|
||||
usbh_stdreq.c \
|
||||
usbh_ioreq.c \
|
||||
usbh_usr.c \
|
||||
usbh_hid_core.c \
|
||||
usbh_hid_mouse.c \
|
||||
usbh_hid_keybd.c \
|
||||
)
|
||||
|
||||
SRC_FATFS = $(addprefix $(FATFS_DIR)/,\
|
||||
ff.c \
|
||||
diskio.c \
|
||||
ccsbcs.c \
|
||||
)
|
||||
|
||||
SRC_CC3K = $(addprefix $(CC3K_DIR)/,\
|
||||
cc3000_common.c \
|
||||
evnt_handler.c \
|
||||
hci.c \
|
||||
netapp.c \
|
||||
nvmem.c \
|
||||
security.c \
|
||||
socket.c \
|
||||
wlan.c \
|
||||
ccspi.c \
|
||||
pybcc3k.c \
|
||||
)
|
||||
|
||||
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o) $(SRC_STMPERIPH:.c=.o) $(SRC_STMUSB:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBD:.c=.o))
|
||||
#OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBH:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o))
|
||||
#OBJ += $(addprefix $(BUILD)/, $(SRC_CC3K:.c=.o))
|
||||
OBJ += $(BUILD)/pins_$(BOARD).o
|
||||
|
||||
all: $(BUILD)/flash.dfu
|
||||
|
||||
$(BUILD)/flash.dfu: $(BUILD)/flash0.bin $(BUILD)/flash1.bin
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(PYTHON) $(DFU) -b 0x08000000:$(BUILD)/flash0.bin -b 0x08020000:$(BUILD)/flash1.bin $@
|
||||
|
||||
$(BUILD)/flash0.bin: $(BUILD)/flash.elf
|
||||
$(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $@
|
||||
|
||||
$(BUILD)/flash1.bin: $(BUILD)/flash.elf
|
||||
$(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $@
|
||||
|
||||
$(BUILD)/flash.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
MAKE_PINS = boards/make-pins.py
|
||||
BOARD_PINS = boards/$(BOARD)/pins.csv
|
||||
AF_FILE = boards/stm32f4xx-af.csv
|
||||
PREFIX_FILE = boards/stm32f4xx-prefix.c
|
||||
GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
|
||||
GEN_PINS_HDR = $(BUILD)/pins.h
|
||||
|
||||
# Making OBJ use an order-only depenedency on the generated pins.h file
|
||||
# has the side effect of making the pins.h file before we actually compile
|
||||
# any of the objects. The normal dependency generation will deal with the
|
||||
# case when pins.h is modified. But when it doesn't exist, we don't know
|
||||
# which source files might need it.
|
||||
$(OBJ): | $(BUILD)/pins.h
|
||||
|
||||
# Use a pattern rule here so that make will only call make-pins.py once to make
|
||||
# both pins_$(BOARD).c and pins.h
|
||||
$(BUILD)/%_$(BOARD).c $(BUILD)/%.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE)
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC)
|
||||
|
||||
$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
|
||||
$(call compile_c)
|
||||
|
||||
include ../py/mkrules.mk
|
||||
300
stm/accel.c
300
stm/accel.c
@@ -1,300 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stm32f4xx.h>
|
||||
#include <stm32f4xx_rcc.h>
|
||||
#include <stm32f4xx_gpio.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "qstr.h"
|
||||
#include "systick.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "accel.h"
|
||||
|
||||
#define ACCEL_ADDR (0x4c)
|
||||
|
||||
void accel_init(void) {
|
||||
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // enable I2C1
|
||||
|
||||
//gpio_pin_init(GPIOB, 6 /* B6 is SCL */, 2 /* AF mode */, 1 /* open drain output */, 1 /* 25 MHz */, 0 /* no pull up or pull down */);
|
||||
//gpio_pin_init(GPIOB, 7 /* B7 is SDA */, 2 /* AF mode */, 1 /* open drain output */, 1 /* 25 MHz */, 0 /* no pull up or pull down */);
|
||||
//gpio_pin_af(GPIOB, 6, 4 /* AF 4 for I2C1 */);
|
||||
//gpio_pin_af(GPIOB, 7, 4 /* AF 4 for I2C1 */);
|
||||
// XXX untested GPIO init! (was above code)
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// PB5 is connected to AVDD; pull high to enable MMA accel device
|
||||
GPIOB->BSRRH = GPIO_Pin_5; // PB5 low to start with
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
// PB6=SCL, PB7=SDA
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
// alternate functions for SCL and SDA
|
||||
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
|
||||
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
|
||||
|
||||
// get clock speeds
|
||||
RCC_ClocksTypeDef rcc_clocks;
|
||||
RCC_GetClocksFreq(&rcc_clocks);
|
||||
|
||||
// disable the I2C peripheral before we configure it
|
||||
I2C1->CR1 &= ~I2C_CR1_PE;
|
||||
|
||||
// program peripheral input clock
|
||||
I2C1->CR2 = 4; // no interrupts; 4 MHz (hopefully!) (could go up to 42MHz)
|
||||
|
||||
// configure clock control reg
|
||||
uint32_t freq = rcc_clocks.PCLK1_Frequency / (100000 << 1); // want 100kHz, this is the formula for freq
|
||||
I2C1->CCR = freq; // standard mode (speed), freq calculated as above
|
||||
|
||||
// configure rise time reg
|
||||
I2C1->TRISE = (rcc_clocks.PCLK1_Frequency / 1000000) + 1; // formula for trise, gives maximum rise time
|
||||
|
||||
// enable the I2C peripheral
|
||||
I2C1->CR1 |= I2C_CR1_PE;
|
||||
|
||||
// wait 20ms, then turn on AVDD, then wait 20ms again; this seems to work, but maybe can decrease delays
|
||||
// doesn't work for soft reboot; 50ms doesn't work either...
|
||||
sys_tick_delay_ms(20);
|
||||
GPIOB->BSRRL = GPIO_Pin_5;
|
||||
sys_tick_delay_ms(20);
|
||||
|
||||
// set START bit in CR1 to generate a start cond!
|
||||
|
||||
// init the chip via I2C commands
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(0);
|
||||
accel_stop();
|
||||
|
||||
/*
|
||||
// read and print all 11 registers
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(0);
|
||||
accel_restart(ACCEL_ADDR, 0);
|
||||
for (int i = 0; i <= 0xa; i++) {
|
||||
int data;
|
||||
if (i == 0xa) {
|
||||
data = accel_read_nack();
|
||||
} else {
|
||||
data = accel_read_ack();
|
||||
}
|
||||
printf(" %02x", data);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
// put into active mode
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(7); // mode
|
||||
accel_send_byte(1); // active mode
|
||||
accel_stop();
|
||||
|
||||
/*
|
||||
// infinite loop to read values
|
||||
for (;;) {
|
||||
sys_tick_delay_ms(500);
|
||||
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(0);
|
||||
accel_restart(ACCEL_ADDR, 0);
|
||||
for (int i = 0; i <= 3; i++) {
|
||||
int data;
|
||||
if (i == 3) {
|
||||
data = accel_read_nack();
|
||||
printf(" %02x\n", data);
|
||||
} else {
|
||||
data = accel_read_ack() & 0x3f;
|
||||
if (data & 0x20) {
|
||||
data |= ~0x1f;
|
||||
}
|
||||
printf(" % 2d", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static uint32_t i2c_get_sr(void) {
|
||||
// must read SR1 first, then SR2, as the read can clear some flags
|
||||
uint32_t sr1 = I2C1->SR1;
|
||||
uint32_t sr2 = I2C1->SR2;
|
||||
return (sr2 << 16) | sr1;
|
||||
}
|
||||
|
||||
void accel_restart(uint8_t addr, int write) {
|
||||
// send start condition
|
||||
I2C1->CR1 |= I2C_CR1_START;
|
||||
|
||||
// wait for BUSY, MSL and SB --> Slave has acknowledged start condition
|
||||
uint32_t timeout = 1000000;
|
||||
while ((i2c_get_sr() & 0x00030001) != 0x00030001) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_restart\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (write) {
|
||||
// send address and write bit
|
||||
I2C1->DR = (addr << 1) | 0;
|
||||
// wait for BUSY, MSL, ADDR, TXE and TRA
|
||||
timeout = 1000000;
|
||||
while ((i2c_get_sr() & 0x00070082) != 0x00070082) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_restart write\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// send address and read bit
|
||||
I2C1->DR = (addr << 1) | 1;
|
||||
// wait for BUSY, MSL and ADDR flags
|
||||
timeout = 1000000;
|
||||
while ((i2c_get_sr() & 0x00030002) != 0x00030002) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_restart read\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void accel_start(uint8_t addr, int write) {
|
||||
// wait until I2C is not busy
|
||||
uint32_t timeout = 1000000;
|
||||
while (I2C1->SR2 & I2C_SR2_BUSY) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_start\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// do rest of start
|
||||
accel_restart(addr, write);
|
||||
}
|
||||
|
||||
void accel_send_byte(uint8_t data) {
|
||||
// send byte
|
||||
I2C1->DR = data;
|
||||
// wait for TRA, BUSY, MSL, TXE and BTF (byte transmitted)
|
||||
uint32_t timeout = 1000000;
|
||||
while ((i2c_get_sr() & 0x00070084) != 0x00070084) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_send_byte\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t accel_read_ack(void) {
|
||||
// enable ACK of received byte
|
||||
I2C1->CR1 |= I2C_CR1_ACK;
|
||||
// wait for BUSY, MSL and RXNE (byte received)
|
||||
uint32_t timeout = 1000000;
|
||||
while ((i2c_get_sr() & 0x00030040) != 0x00030040) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_read_ack\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// read and return data
|
||||
uint8_t data = I2C1->DR;
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t accel_read_nack(void) {
|
||||
// disable ACK of received byte (to indicate end of receiving)
|
||||
I2C1->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK);
|
||||
// last byte should apparently also generate a stop condition
|
||||
I2C1->CR1 |= I2C_CR1_STOP;
|
||||
// wait for BUSY, MSL and RXNE (byte received)
|
||||
uint32_t timeout = 1000000;
|
||||
while ((i2c_get_sr() & 0x00030040) != 0x00030040) {
|
||||
if (--timeout == 0) {
|
||||
printf("timeout in accel_read_nack\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// read and return data
|
||||
uint8_t data = I2C1->DR;
|
||||
return data;
|
||||
}
|
||||
|
||||
void accel_stop(void) {
|
||||
// send stop condition
|
||||
I2C1->CR1 |= I2C_CR1_STOP;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Micro Python bindings */
|
||||
|
||||
int accel_buf[12];
|
||||
|
||||
mp_obj_t pyb_accel_read(void) {
|
||||
for (int i = 0; i <= 6; i += 3) {
|
||||
accel_buf[0 + i] = accel_buf[0 + i + 3];
|
||||
accel_buf[1 + i] = accel_buf[1 + i + 3];
|
||||
accel_buf[2 + i] = accel_buf[2 + i + 3];
|
||||
}
|
||||
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(0);
|
||||
accel_restart(ACCEL_ADDR, 0);
|
||||
for (int i = 0; i <= 2; i++) {
|
||||
int v = accel_read_ack() & 0x3f;
|
||||
if (v & 0x20) {
|
||||
v |= ~0x1f;
|
||||
}
|
||||
accel_buf[9 + i] = v;
|
||||
}
|
||||
int jolt_info = accel_read_nack();
|
||||
|
||||
mp_obj_t data[4];
|
||||
data[0] = mp_obj_new_int(accel_buf[0] + accel_buf[3] + accel_buf[6] + accel_buf[9]);
|
||||
data[1] = mp_obj_new_int(accel_buf[1] + accel_buf[4] + accel_buf[7] + accel_buf[10]);
|
||||
data[2] = mp_obj_new_int(accel_buf[2] + accel_buf[5] + accel_buf[8] + accel_buf[11]);
|
||||
data[3] = mp_obj_new_int(jolt_info);
|
||||
|
||||
return mp_obj_new_tuple(4, data);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(pyb_accel_read_obj, pyb_accel_read);
|
||||
|
||||
mp_obj_t pyb_accel_read_all(void) {
|
||||
mp_obj_t data[11];
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(0);
|
||||
accel_restart(ACCEL_ADDR, 0);
|
||||
for (int i = 0; i <= 9; i++) {
|
||||
data[i] = mp_obj_new_int(accel_read_ack());
|
||||
}
|
||||
data[10] = mp_obj_new_int(accel_read_nack());
|
||||
|
||||
return mp_obj_new_tuple(11, data);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(pyb_accel_read_all_obj, pyb_accel_read_all);
|
||||
|
||||
mp_obj_t pyb_accel_write_mode(mp_obj_t o_int, mp_obj_t o_mode) {
|
||||
accel_start(ACCEL_ADDR, 1);
|
||||
accel_send_byte(6); // start at int
|
||||
accel_send_byte(mp_obj_get_int(o_int));
|
||||
accel_send_byte(mp_obj_get_int(o_mode));
|
||||
accel_stop();
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_write_mode_obj, pyb_accel_write_mode);
|
||||
11
stm/accel.h
11
stm/accel.h
@@ -1,11 +0,0 @@
|
||||
void accel_init(void);
|
||||
void accel_restart(uint8_t addr, int write);
|
||||
void accel_start(uint8_t addr, int write);
|
||||
void accel_send_byte(uint8_t data);
|
||||
uint8_t accel_read_ack(void);
|
||||
uint8_t accel_read_nack(void);
|
||||
void accel_stop(void);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_accel_read_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_accel_read_all_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_accel_write_mode_obj);
|
||||
446
stm/adc.c
446
stm/adc.c
@@ -1,446 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stm32f4xx.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "adc.h"
|
||||
|
||||
/* ADC defintions */
|
||||
#define ADCx (ADC1)
|
||||
#define ADCx_CLK (RCC_APB2Periph_ADC1)
|
||||
#define ADC_NUM_CHANNELS (16)
|
||||
|
||||
/* Internally connected ADC channels Temp/VBAT/VREF*/
|
||||
#if defined (STM32F40XX) || defined(STM32F41XX) || defined(STM32F40_41xxx)
|
||||
#define ADC_TEMP_CHANNEL (16)
|
||||
#define ADC_VBAT_CHANNEL (18)
|
||||
#define ADC_VREF_CHANNEL (17)
|
||||
#elif defined (STM32F42XX) || defined(STM32F43XX)
|
||||
#define ADC_TEMP_CHANNEL (18)
|
||||
#define ADC_VBAT_CHANNEL (18) /* same channel as TEMP */
|
||||
#define ADC_VREF_CHANNEL (17)
|
||||
#endif
|
||||
|
||||
/* Core temperature sensor definitions */
|
||||
#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */
|
||||
#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */
|
||||
|
||||
/* VBAT divider */
|
||||
#if defined (STM32F40XX) || defined(STM32F41XX) || defined(STM32F40_41xxx)
|
||||
#define VBAT_DIV (2)
|
||||
#elif defined (STM32F42XX) || defined(STM32F43XX)
|
||||
#define VBAT_DIV (4)
|
||||
#endif
|
||||
|
||||
/* GPIO struct */
|
||||
typedef struct {
|
||||
GPIO_TypeDef* port;
|
||||
uint32_t pin;
|
||||
} gpio_t;
|
||||
|
||||
/* ADC GPIOs */
|
||||
static const gpio_t adc_gpio[] = {
|
||||
{GPIOA, GPIO_Pin_0}, /* ADC123_IN0 */
|
||||
{GPIOA, GPIO_Pin_1}, /* ADC123_IN1 */
|
||||
{GPIOA, GPIO_Pin_2}, /* ADC123_IN2 */
|
||||
{GPIOA, GPIO_Pin_3}, /* ADC123_IN3 */
|
||||
{GPIOA, GPIO_Pin_4}, /* ADC12_IN4 */
|
||||
{GPIOA, GPIO_Pin_5}, /* ADC12_IN5 */
|
||||
{GPIOA, GPIO_Pin_6}, /* ADC12_IN6 */
|
||||
{GPIOA, GPIO_Pin_7}, /* ADC12_IN7 */
|
||||
{GPIOB, GPIO_Pin_0}, /* ADC12_IN8 */
|
||||
{GPIOB, GPIO_Pin_1}, /* ADC12_IN9 */
|
||||
{GPIOC, GPIO_Pin_0}, /* ADC123_IN10 */
|
||||
{GPIOC, GPIO_Pin_1}, /* ADC123_IN11 */
|
||||
{GPIOC, GPIO_Pin_2}, /* ADC123_IN12 */
|
||||
{GPIOC, GPIO_Pin_3}, /* ADC123_IN13 */
|
||||
{GPIOC, GPIO_Pin_4}, /* ADC12_IN14 */
|
||||
{GPIOC, GPIO_Pin_5}, /* ADC12_IN15 */
|
||||
|
||||
};
|
||||
|
||||
void adc_init_all(uint32_t resolution) {
|
||||
ADC_InitTypeDef ADC_InitStructure;
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
ADC_CommonInitTypeDef ADC_CommonInitStructure;
|
||||
|
||||
/* Enable ADCx, DMA and GPIO clocks */
|
||||
#if 0
|
||||
/* GPIO clocks enabled in main */
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
|
||||
RCC_AHB1Periph_GPIOB |
|
||||
RCC_AHB1Periph_GPIOC, ENABLE);
|
||||
#endif
|
||||
RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
|
||||
|
||||
/* ADC Common Init */
|
||||
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
|
||||
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
|
||||
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
|
||||
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
|
||||
ADC_CommonInit(&ADC_CommonInitStructure);
|
||||
|
||||
/* Configure ADC GPIOs */
|
||||
for (int i=0; i<ADC_NUM_CHANNELS; i++) {
|
||||
GPIO_InitStructure.GPIO_Pin = adc_gpio[i].pin;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(adc_gpio[i].port, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
/* ADCx Init */
|
||||
// ADC_DeInit();
|
||||
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
|
||||
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
|
||||
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
|
||||
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
|
||||
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
|
||||
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
|
||||
ADC_InitStructure.ADC_NbrOfConversion = 1;
|
||||
ADC_Init(ADCx, &ADC_InitStructure);
|
||||
|
||||
/* Enable ADCx */
|
||||
ADC_Cmd(ADCx, ENABLE);
|
||||
|
||||
/* Enable VBAT/VREF monitor */
|
||||
ADC_VBATCmd(ENABLE);
|
||||
|
||||
/* Enable temperature sensor */
|
||||
ADC_TempSensorVrefintCmd(ENABLE);
|
||||
}
|
||||
|
||||
void adc_init_single(uint32_t channel) {
|
||||
ADC_InitTypeDef ADC_InitStructure;
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
ADC_CommonInitTypeDef ADC_CommonInitStructure;
|
||||
|
||||
/* Enable ADCx, DMA and GPIO clocks */
|
||||
#if 0
|
||||
/* GPIO clocks enabled in main */
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
|
||||
RCC_AHB1Periph_GPIOB |
|
||||
RCC_AHB1Periph_GPIOC, ENABLE);
|
||||
#endif
|
||||
RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
|
||||
|
||||
/* ADC Common Init */
|
||||
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
|
||||
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
|
||||
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
|
||||
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
|
||||
ADC_CommonInit(&ADC_CommonInitStructure);
|
||||
|
||||
/* Configure ADC GPIO for the single channel */
|
||||
GPIO_InitStructure.GPIO_Pin = adc_gpio[channel].pin;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(adc_gpio[channel].port, &GPIO_InitStructure);
|
||||
|
||||
/* ADCx Init */
|
||||
// ADC_DeInit();
|
||||
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
|
||||
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
|
||||
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
|
||||
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
|
||||
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
|
||||
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
|
||||
ADC_InitStructure.ADC_NbrOfConversion = 1;
|
||||
ADC_Init(ADCx, &ADC_InitStructure);
|
||||
|
||||
/* Enable ADCx */
|
||||
ADC_Cmd(ADCx, ENABLE);
|
||||
|
||||
/* Enable VBAT/VREF monitor */
|
||||
ADC_VBATCmd(ENABLE);
|
||||
|
||||
/* Enable temperature sensor */
|
||||
ADC_TempSensorVrefintCmd(ENABLE);
|
||||
}
|
||||
|
||||
uint32_t adc_read_channel(int channel)
|
||||
{
|
||||
int timeout = 10000;
|
||||
|
||||
if (channel > (ADC_NUM_CHANNELS-1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ADC regular channel config ADC/Channel/SEQ Rank/Sample time */
|
||||
ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_15Cycles);
|
||||
|
||||
/* Start ADC single conversion */
|
||||
ADC_SoftwareStartConv(ADCx);
|
||||
|
||||
/* Wait for conversion to be complete*/
|
||||
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
|
||||
}
|
||||
|
||||
/* ADC conversion timed out */
|
||||
if (timeout == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return converted data */
|
||||
return ADC_GetConversionValue(ADCx);
|
||||
}
|
||||
|
||||
int adc_read_core_temp()
|
||||
{
|
||||
int timeout = 10000;
|
||||
|
||||
/* ADC temperature sensor channel config ADC/Channel/SEQ Rank/Sample time */
|
||||
/* Note: sample time must be higher than minimum sample time */
|
||||
ADC_RegularChannelConfig(ADCx, ADC_TEMP_CHANNEL, 1, ADC_SampleTime_480Cycles);
|
||||
|
||||
/* Start ADC single conversion */
|
||||
ADC_SoftwareStartConv(ADCx);
|
||||
|
||||
/* Wait for conversion to be complete*/
|
||||
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
|
||||
}
|
||||
|
||||
/* ADC conversion timed out */
|
||||
if (timeout == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert ADC reading to temperature */
|
||||
/* Temperature formula from datasheet P.411 */
|
||||
return ((ADC_GetConversionValue(ADCx) - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
|
||||
}
|
||||
|
||||
float adc_read_core_vbat()
|
||||
{
|
||||
int timeout = 10000;
|
||||
|
||||
/* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
|
||||
/* Note: sample time must be higher than minimum sample time */
|
||||
ADC_RegularChannelConfig(ADCx, ADC_VBAT_CHANNEL, 1, ADC_SampleTime_144Cycles);
|
||||
|
||||
/* Start ADC single conversion */
|
||||
ADC_SoftwareStartConv(ADCx);
|
||||
|
||||
/* Wait for conversion to be complete */
|
||||
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
|
||||
}
|
||||
|
||||
/* ADC conversion timed out */
|
||||
if (timeout == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert ADC reading to voltage, VBAT pin is
|
||||
internally connected to a bridge divider by VBAT_DIV */
|
||||
return ADC_GetConversionValue(ADCx)*VBAT_DIV/4096.0f*3.3f;
|
||||
}
|
||||
|
||||
float adc_read_core_vref()
|
||||
{
|
||||
int timeout = 10000;
|
||||
|
||||
/* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
|
||||
/* Note: sample time must be higher than minimum sample time */
|
||||
ADC_RegularChannelConfig(ADCx, ADC_VREF_CHANNEL, 1, ADC_SampleTime_112Cycles);
|
||||
|
||||
/* Start ADC single conversion */
|
||||
ADC_SoftwareStartConv(ADCx);
|
||||
|
||||
/* Wait for conversion to be complete*/
|
||||
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
|
||||
}
|
||||
|
||||
/* ADC conversion timed out */
|
||||
if (timeout == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert ADC reading to voltage */
|
||||
return ADC_GetConversionValue(ADCx)/4096.0f*3.3f;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Micro Python bindings : adc_all object */
|
||||
|
||||
typedef struct _pyb_obj_adc_all_t {
|
||||
mp_obj_base_t base;
|
||||
bool is_enabled;
|
||||
} pyb_obj_adc_all_t;
|
||||
|
||||
static void adc_all_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
print(env, "<ADC all>");
|
||||
}
|
||||
|
||||
static mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) {
|
||||
pyb_obj_adc_all_t *self = self_in;
|
||||
|
||||
if (self->is_enabled) {
|
||||
uint32_t chan = mp_obj_get_int(channel);
|
||||
uint32_t data = adc_read_channel(chan);
|
||||
return mp_obj_new_int(data);
|
||||
} else {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
static mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) {
|
||||
pyb_obj_adc_all_t *self = self_in;
|
||||
|
||||
if (self->is_enabled) {
|
||||
int data = adc_read_core_temp();
|
||||
return mp_obj_new_int(data);
|
||||
} else {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
static mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) {
|
||||
pyb_obj_adc_all_t *self = self_in;
|
||||
|
||||
if (self->is_enabled) {
|
||||
float data = adc_read_core_vbat();
|
||||
return mp_obj_new_float(data);
|
||||
} else {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
static mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) {
|
||||
pyb_obj_adc_all_t *self = self_in;
|
||||
|
||||
if (self->is_enabled) {
|
||||
float data = adc_read_core_vref();
|
||||
return mp_obj_new_float(data);
|
||||
} else {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
|
||||
|
||||
STATIC const mp_map_elem_t adc_all_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_channel), (mp_obj_t) &adc_all_read_channel_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_core_temp), (mp_obj_t)&adc_all_read_core_temp_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vbat), (mp_obj_t)&adc_all_read_core_vbat_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vref), (mp_obj_t)&adc_all_read_core_vref_obj},
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);
|
||||
|
||||
static const mp_obj_type_t adc_all_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADC,
|
||||
.print = adc_all_print,
|
||||
.locals_dict = (mp_obj_t)&adc_all_locals_dict,
|
||||
};
|
||||
|
||||
mp_obj_t pyb_ADC_all(mp_obj_t resolution) {
|
||||
/* init ADC */
|
||||
adc_init_all(mp_obj_get_int(resolution));
|
||||
|
||||
pyb_obj_adc_all_t *o = m_new_obj(pyb_obj_adc_all_t);
|
||||
o->base.type = &adc_all_type;
|
||||
o->is_enabled = true;
|
||||
return o;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_all_obj, pyb_ADC_all);
|
||||
|
||||
/******************************************************************************/
|
||||
/* Micro Python bindings : adc object (single channel) */
|
||||
|
||||
typedef struct _pyb_obj_adc_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t pin_name;
|
||||
int channel;
|
||||
bool is_enabled;
|
||||
} pyb_obj_adc_t;
|
||||
|
||||
static void adc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_obj_adc_t *self = self_in;
|
||||
print(env, "<ADC on ");
|
||||
mp_obj_print_helper(print, env, self->pin_name, PRINT_STR);
|
||||
print(env, " channel=%lu>", self->channel);
|
||||
}
|
||||
|
||||
static mp_obj_t adc_read(mp_obj_t self_in) {
|
||||
pyb_obj_adc_t *self = self_in;
|
||||
|
||||
if (self->is_enabled) {
|
||||
uint32_t data = adc_read_channel(self->channel);
|
||||
return mp_obj_new_int(data);
|
||||
} else {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
|
||||
|
||||
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
|
||||
|
||||
static const mp_obj_type_t adc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADC,
|
||||
.print = adc_print,
|
||||
.locals_dict = (mp_obj_t)&adc_locals_dict,
|
||||
};
|
||||
|
||||
mp_obj_t pyb_ADC(mp_obj_t pin_name_obj) {
|
||||
|
||||
pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t);
|
||||
o->base.type = &adc_type;
|
||||
o->pin_name = pin_name_obj;
|
||||
|
||||
// work out the channel from the pin name
|
||||
const char *pin_name = mp_obj_str_get_str(pin_name_obj);
|
||||
GPIO_TypeDef *port;
|
||||
switch (pin_name[0]) {
|
||||
case 'A': case 'a': port = GPIOA; break;
|
||||
case 'B': case 'b': port = GPIOB; break;
|
||||
case 'C': case 'c': port = GPIOC; break;
|
||||
default: goto pin_error;
|
||||
}
|
||||
uint pin_num = 0;
|
||||
for (const char *s = pin_name + 1; *s; s++) {
|
||||
if (!('0' <= *s && *s <= '9')) {
|
||||
goto pin_error;
|
||||
}
|
||||
pin_num = 10 * pin_num + *s - '0';
|
||||
}
|
||||
if (!(0 <= pin_num && pin_num <= 15)) {
|
||||
goto pin_error;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ADC_NUM_CHANNELS; i++) {
|
||||
if (adc_gpio[i].port == port && adc_gpio[i].pin == (1 << pin_num)) {
|
||||
o->channel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ADC_NUM_CHANNELS) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin_name));
|
||||
}
|
||||
|
||||
// init ADC just for this channel
|
||||
adc_init_single(o->channel);
|
||||
|
||||
o->is_enabled = true;
|
||||
|
||||
return o;
|
||||
|
||||
pin_error:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not exist", pin_name));
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_obj, pyb_ADC);
|
||||
@@ -1,2 +0,0 @@
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_ADC_all_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_ADC_obj);
|
||||
256
stm/audio.c
256
stm/audio.c
@@ -1,256 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "stm32f4xx_dac.h"
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
STATIC void TIM7_Config(uint freq) {
|
||||
// TIM7 clock enable
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
|
||||
// reset TIM7
|
||||
TIM_DeInit(TIM7);
|
||||
|
||||
// Compute the prescaler value so TIM7 triggers at freq-Hz
|
||||
uint16_t period = (uint16_t) ((SystemCoreClock / 2) / freq) - 1;
|
||||
|
||||
// Time base configuration
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||
TIM_TimeBaseStructure.TIM_Period = period; // timer triggers with this period
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = 0; // timer runs at SystemCoreClock / 2
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // unused for TIM7
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // unused for TIM7
|
||||
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
|
||||
|
||||
// TIM7 TRGO selection
|
||||
TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update);
|
||||
|
||||
// TIM7 enable counter
|
||||
TIM_Cmd(TIM7, ENABLE);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
typedef struct _pyb_audio_t {
|
||||
mp_obj_base_t base;
|
||||
uint dac_channel; // DAC_Channel_1 or DAC_Channel_2
|
||||
DMA_Stream_TypeDef *dma_stream; // DMA1_Stream6 or DMA1_Stream7
|
||||
} pyb_audio_t;
|
||||
|
||||
mp_obj_t pyb_audio_noise(mp_obj_t self_in, mp_obj_t freq) {
|
||||
pyb_audio_t *self = self_in;
|
||||
|
||||
// set TIM7 to trigger the DAC at the given frequency
|
||||
TIM7_Config(mp_obj_get_int(freq));
|
||||
|
||||
DAC_Cmd(self->dac_channel, DISABLE);
|
||||
|
||||
DAC_InitTypeDef DAC_InitStructure;
|
||||
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
|
||||
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Noise;
|
||||
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits10_0;
|
||||
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
|
||||
DAC_Init(self->dac_channel, &DAC_InitStructure);
|
||||
|
||||
DAC_Cmd(self->dac_channel, ENABLE);
|
||||
|
||||
if (self->dac_channel == DAC_Channel_1) {
|
||||
DAC_SetChannel1Data(DAC_Align_12b_L, 0x7ff0);
|
||||
} else {
|
||||
DAC_SetChannel2Data(DAC_Align_12b_L, 0x7ff0);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t pyb_audio_triangle(mp_obj_t self_in, mp_obj_t freq) {
|
||||
pyb_audio_t *self = self_in;
|
||||
|
||||
// set TIM7 to trigger the DAC at the given frequency
|
||||
TIM7_Config(mp_obj_get_int(freq));
|
||||
|
||||
DAC_Cmd(self->dac_channel, DISABLE);
|
||||
|
||||
DAC_InitTypeDef DAC_InitStructure;
|
||||
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
|
||||
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Triangle;
|
||||
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023;
|
||||
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
|
||||
DAC_Init(self->dac_channel, &DAC_InitStructure);
|
||||
|
||||
DAC_Cmd(self->dac_channel, ENABLE);
|
||||
|
||||
// set base value of triangle wave
|
||||
if (self->dac_channel == DAC_Channel_1) {
|
||||
DAC_SetChannel1Data(DAC_Align_12b_R, 0x100);
|
||||
} else {
|
||||
DAC_SetChannel2Data(DAC_Align_12b_R, 0x100);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// direct access to DAC
|
||||
mp_obj_t pyb_audio_dac(mp_obj_t self_in, mp_obj_t val) {
|
||||
pyb_audio_t *self = self_in;
|
||||
if (self->dac_channel == DAC_Channel_1) {
|
||||
DAC_SetChannel1Data(DAC_Align_8b_R, mp_obj_get_int(val));
|
||||
} else {
|
||||
DAC_SetChannel2Data(DAC_Align_8b_R, mp_obj_get_int(val));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
#define DAC_DHR8R1_ADDRESS (DAC_BASE + 0x10)
|
||||
#define DAC_DHR8R2_ADDRESS (DAC_BASE + 0x1c)
|
||||
|
||||
// initiates a burst of RAM->DAC using DMA
|
||||
// input data is treated as an array of bytes (8 bit data)
|
||||
// TIM7 is used to set the frequency of the transfer
|
||||
mp_obj_t pyb_audio_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
pyb_audio_t *self = args[0];
|
||||
|
||||
// set TIM7 to trigger the DAC at the given frequency
|
||||
TIM7_Config(mp_obj_get_int(args[2]));
|
||||
|
||||
mp_obj_type_t *type = mp_obj_get_type(args[1]);
|
||||
if (type->buffer_p.get_buffer == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol"));
|
||||
}
|
||||
mp_buffer_info_t bufinfo;
|
||||
type->buffer_p.get_buffer(args[1], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
|
||||
|
||||
DMA_Cmd(self->dma_stream, DISABLE);
|
||||
while (DMA_GetCmdStatus(self->dma_stream) != DISABLE) {
|
||||
}
|
||||
|
||||
DAC_Cmd(self->dac_channel, DISABLE);
|
||||
|
||||
// DAC channel configuration
|
||||
DAC_InitTypeDef DAC_InitStructure;
|
||||
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
|
||||
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
|
||||
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value
|
||||
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
|
||||
DAC_Init(self->dac_channel, &DAC_InitStructure);
|
||||
|
||||
// DMA1_Stream[67] channel7 configuration
|
||||
DMA_DeInit(self->dma_stream);
|
||||
DMA_InitTypeDef DMA_InitStructure;
|
||||
DMA_InitStructure.DMA_Channel = DMA_Channel_7;
|
||||
if (self->dac_channel == DAC_Channel_1) {
|
||||
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_ADDRESS;
|
||||
} else {
|
||||
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R2_ADDRESS;
|
||||
}
|
||||
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)bufinfo.buf;
|
||||
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
|
||||
DMA_InitStructure.DMA_BufferSize = bufinfo.len;
|
||||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||||
mp_map_elem_t *kw_mode = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("mode")), MP_MAP_LOOKUP);
|
||||
DMA_InitStructure.DMA_Mode = kw_mode == NULL ? DMA_Mode_Normal : mp_obj_get_int(kw_mode->value); // normal = 0, circular = 0x100
|
||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
|
||||
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
|
||||
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
|
||||
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
|
||||
DMA_Init(self->dma_stream, &DMA_InitStructure);
|
||||
|
||||
// enable DMA stream
|
||||
DMA_Cmd(self->dma_stream, ENABLE);
|
||||
while (DMA_GetCmdStatus(self->dma_stream) == DISABLE) {
|
||||
}
|
||||
|
||||
// enable DAC channel
|
||||
DAC_Cmd(self->dac_channel, ENABLE);
|
||||
|
||||
// enable DMA for DAC channel
|
||||
DAC_DMACmd(self->dac_channel, ENABLE);
|
||||
|
||||
//printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_noise_obj, pyb_audio_noise);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_triangle_obj, pyb_audio_triangle);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_dac_obj, pyb_audio_dac);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_audio_dma_obj, 3, pyb_audio_dma);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_audio_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_audio_noise_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_triangle), (mp_obj_t)&pyb_audio_triangle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dac), (mp_obj_t)&pyb_audio_dac_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dma), (mp_obj_t)&pyb_audio_dma_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_audio_locals_dict, pyb_audio_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pyb_audio_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_,
|
||||
.locals_dict = (mp_obj_t)&pyb_audio_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const pyb_audio_t pyb_audio_channel_1 = {{&pyb_audio_type}, DAC_Channel_1, DMA1_Stream5};
|
||||
STATIC const pyb_audio_t pyb_audio_channel_2 = {{&pyb_audio_type}, DAC_Channel_2, DMA1_Stream6};
|
||||
|
||||
// create the audio object
|
||||
// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
|
||||
|
||||
STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
|
||||
// DAC peripheral clock
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
|
||||
|
||||
int dac_id = mp_obj_get_int(id);
|
||||
uint pin;
|
||||
const pyb_audio_t *dac_obj;
|
||||
|
||||
if (dac_id == 1) {
|
||||
pin = GPIO_Pin_4;
|
||||
dac_obj = &pyb_audio_channel_1;
|
||||
} else {
|
||||
pin = GPIO_Pin_5;
|
||||
dac_obj = &pyb_audio_channel_2;
|
||||
}
|
||||
|
||||
// DAC channel configuration
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_InitStructure.GPIO_Pin = pin;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
// DAC channel Configuration
|
||||
DAC_InitTypeDef DAC_InitStructure;
|
||||
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
|
||||
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
|
||||
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023;
|
||||
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
|
||||
DAC_Init(dac_obj->dac_channel, &DAC_InitStructure);
|
||||
|
||||
// Enable DAC Channel
|
||||
DAC_Cmd(dac_obj->dac_channel, ENABLE);
|
||||
|
||||
// from now on use DAC_SetChannel[12]Data to trigger a conversion
|
||||
|
||||
// return static object
|
||||
return (mp_obj_t)dac_obj;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_Audio_obj, pyb_Audio);
|
||||
@@ -1 +0,0 @@
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_Audio_obj);
|
||||
@@ -1,38 +0,0 @@
|
||||
#define NETDUINO_PLUS_2
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "NetduinoPlus2"
|
||||
|
||||
#define MICROPY_HW_HAS_SWITCH (1)
|
||||
|
||||
// On the netuino, the sdcard appears to be wired up as a 1-bit
|
||||
// SPI, so the driver needs to be converted to support that before
|
||||
// we can turn this on.
|
||||
#define MICROPY_HW_HAS_SDCARD (0)
|
||||
#define MICROPY_HW_HAS_MMA7660 (0)
|
||||
#define MICROPY_HW_HAS_LIS3DSH (0)
|
||||
#define MICROPY_HW_HAS_LCD (0)
|
||||
#define MICROPY_HW_HAS_WLAN (0)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
#define MICROPY_HW_ENABLE_RTC (0)
|
||||
#define MICROPY_HW_ENABLE_TIMER (1)
|
||||
#define MICROPY_HW_ENABLE_SERVO (1)
|
||||
#define MICROPY_HW_ENABLE_AUDIO (0)
|
||||
|
||||
// USRSW is pulled low. Pressing the button makes the input go high.
|
||||
#define USRSW_PIN (pin_B11)
|
||||
#define USRSW_PUPD (GPIO_PuPd_NOPULL)
|
||||
#define USRSW_EXTI_EDGE (EXTI_Trigger_Rising)
|
||||
#define USRSW_PRESSED (1)
|
||||
|
||||
/* LED */
|
||||
#define PYB_LED1 (pin_A10) // Blue LED
|
||||
#define PYB_LED2 (pin_C13) // White LED (aka Power)
|
||||
#define PYB_LED3 (pin_A10) // Same as Led(1)
|
||||
#define PYB_LED4 (pin_C13) // Same as Led(2)
|
||||
|
||||
#define PYB_OTYPE (GPIO_OType_PP)
|
||||
|
||||
#define PYB_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
|
||||
#define PYB_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
|
||||
|
||||
#define HSE_VALUE (25000000)
|
||||
@@ -1,28 +0,0 @@
|
||||
D0,PC7
|
||||
D1,PC6
|
||||
D2,PA3
|
||||
D3,PA2
|
||||
D4,PB12
|
||||
D5,PB8
|
||||
D6,PB9
|
||||
D7,PA1
|
||||
D8,PA0
|
||||
D9,PA6
|
||||
D10,PB10
|
||||
D11,PB15
|
||||
D12,PB14
|
||||
D13,PB13
|
||||
A0,PC0
|
||||
A1,PC1
|
||||
A2,PC2
|
||||
A3,PC3
|
||||
A4,PC4
|
||||
A5,PC5
|
||||
LED,PA10
|
||||
SW,PB11
|
||||
PWR_LED,PC13
|
||||
PWR_SD,PB1
|
||||
PWR_HDR,PB2
|
||||
PWR_ETH,PC15
|
||||
RST_ETH,PD2
|
||||
|
||||
|
@@ -1,32 +0,0 @@
|
||||
#define PYBOARD3
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "PYBv3"
|
||||
|
||||
#define MICROPY_HW_HAS_SWITCH (1)
|
||||
#define MICROPY_HW_HAS_SDCARD (1)
|
||||
#define MICROPY_HW_HAS_MMA7660 (1)
|
||||
#define MICROPY_HW_HAS_LIS3DSH (0)
|
||||
#define MICROPY_HW_HAS_LCD (0)
|
||||
#define MICROPY_HW_HAS_WLAN (0)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
#define MICROPY_HW_ENABLE_RTC (1)
|
||||
#define MICROPY_HW_ENABLE_TIMER (1)
|
||||
#define MICROPY_HW_ENABLE_SERVO (1)
|
||||
#define MICROPY_HW_ENABLE_AUDIO (0)
|
||||
|
||||
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
|
||||
#define USRSW_PIN (pin_A13)
|
||||
#define USRSW_PUPD (GPIO_PuPd_UP)
|
||||
#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling)
|
||||
#define USRSW_PRESSED (0)
|
||||
|
||||
/* LED */
|
||||
#define PYB_LED1 (pin_A8) // R1 - red
|
||||
#define PYB_LED2 (pin_A10) // R2 - red
|
||||
#define PYB_LED3 (pin_C4) // G1 - green
|
||||
#define PYB_LED4 (pin_C5) // G2 - green
|
||||
|
||||
#define PYB_OTYPE (GPIO_OType_PP)
|
||||
|
||||
#define PYB_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask)
|
||||
#define PYB_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask)
|
||||
@@ -1,37 +0,0 @@
|
||||
B13,PB13
|
||||
B14,PB14
|
||||
B15,PB15
|
||||
C6,PC6
|
||||
C7,PC7
|
||||
A13,PA13
|
||||
A14,PA14
|
||||
A15,PA15
|
||||
B3,PB3
|
||||
B4,PB4
|
||||
B6,PB6
|
||||
B7,PB7
|
||||
B8,PB8
|
||||
B9,PB9
|
||||
C0,PC0
|
||||
C1,PC1
|
||||
C2,PC2
|
||||
C3,PC3
|
||||
A0,PA0
|
||||
A1,PA1
|
||||
A2,PA2
|
||||
A3,PA3
|
||||
A4,PA4
|
||||
A5,PA5
|
||||
A6,PA6
|
||||
A7,PA7
|
||||
B0,PB0
|
||||
B1,PB1
|
||||
B10,PB10
|
||||
B11,PB11
|
||||
B12,PB12
|
||||
LED_R1,PA8
|
||||
LED_R2,PA10
|
||||
LED_G1,PC4
|
||||
LED_G2,PC5
|
||||
SW,PA13
|
||||
|
||||
|
@@ -1,33 +0,0 @@
|
||||
#define PYBOARD4
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "PYBv4"
|
||||
|
||||
#define MICROPY_HW_HAS_SWITCH (1)
|
||||
#define MICROPY_HW_HAS_SDCARD (1)
|
||||
#define MICROPY_HW_HAS_MMA7660 (1)
|
||||
#define MICROPY_HW_HAS_LIS3DSH (0)
|
||||
#define MICROPY_HW_HAS_LCD (1)
|
||||
#define MICROPY_HW_HAS_WLAN (0)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
#define MICROPY_HW_ENABLE_RTC (1)
|
||||
#define MICROPY_HW_ENABLE_TIMER (1)
|
||||
#define MICROPY_HW_ENABLE_SERVO (1)
|
||||
#define MICROPY_HW_ENABLE_AUDIO (1)
|
||||
|
||||
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
|
||||
#define USRSW_PIN (pin_B3)
|
||||
#define USRSW_PUPD (GPIO_PuPd_UP)
|
||||
#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling)
|
||||
#define USRSW_PRESSED (0)
|
||||
|
||||
/* LED */
|
||||
#define PYB_LED1 (pin_A13) // red
|
||||
#define PYB_LED2 (pin_A14) // green
|
||||
#define PYB_LED3 (pin_A15) // yellow
|
||||
#define PYB_LED4 (pin_B4) // blue
|
||||
|
||||
#define PYB_OTYPE (GPIO_OType_PP)
|
||||
|
||||
#define PYB_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
|
||||
#define PYB_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
X1,PA0
|
||||
X2,PA1
|
||||
X3,PA2
|
||||
X4,PA3
|
||||
X5,PA4
|
||||
X6,PA5
|
||||
X7,PA6
|
||||
X8,PA7
|
||||
X9,PB6
|
||||
X10,PB7
|
||||
X11,PC4
|
||||
X12,PC5
|
||||
X13,Reset
|
||||
X14,GND
|
||||
X15,3.3V
|
||||
X16,VIN
|
||||
X17,PB3
|
||||
X18,PC13
|
||||
X19,PC0
|
||||
X20,PC1
|
||||
X21,PC2
|
||||
X22,PC3
|
||||
X23,A3.3V
|
||||
X24,AGND
|
||||
Y1,PC6
|
||||
Y2,PC7
|
||||
Y3,PB8
|
||||
Y4,PB9
|
||||
Y5,PB12
|
||||
Y6,PB13
|
||||
Y7,PB14
|
||||
Y8,PB15
|
||||
Y9,PB10
|
||||
Y10,PB11
|
||||
Y11,PB0
|
||||
Y12,PB1
|
||||
Y13,Reset
|
||||
Y14,GND
|
||||
Y15,3.3V
|
||||
Y16,VIN
|
||||
LED_BLUE,PB4
|
||||
LED_RED,PA13
|
||||
LED_GREEN,PA14
|
||||
LED_YELLOW,PA15
|
||||
SW,PB3
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user