Merge branch 'master' of github.com:micropython/micropython
This commit is contained in:
commit
09e1f43200
3
py/obj.h
3
py/obj.h
@ -395,3 +395,6 @@ typedef struct _mp_obj_classmethod_t {
|
||||
|
||||
// sequence helpers
|
||||
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest);
|
||||
bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end);
|
||||
#define m_seq_copy(dest, src, len, item_sz) memcpy(dest, src, len * sizeof(item_sz))
|
||||
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2);
|
||||
|
12
py/objlist.c
12
py/objlist.c
@ -136,7 +136,17 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
switch (op) {
|
||||
case RT_BINARY_OP_SUBSCR:
|
||||
{
|
||||
// list load
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
if (MP_OBJ_IS_TYPE(rhs, &slice_type)) {
|
||||
machine_uint_t start, stop;
|
||||
if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) {
|
||||
assert(0);
|
||||
}
|
||||
mp_obj_list_t *res = list_new(stop - start);
|
||||
m_seq_copy(res->items, o->items + start, res->len, mp_obj_t);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
uint index = mp_get_index(o->base.type, o->len, rhs);
|
||||
return o->items[index];
|
||||
}
|
||||
|
34
py/objstr.c
34
py/objstr.c
@ -115,25 +115,9 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
}
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &slice_type)) {
|
||||
machine_int_t start, stop, step;
|
||||
mp_obj_slice_get(rhs_in, &start, &stop, &step);
|
||||
assert(step == 1);
|
||||
if (start < 0) {
|
||||
start = lhs_len + start;
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
} else if (start > lhs_len) {
|
||||
start = lhs_len;
|
||||
}
|
||||
if (stop <= 0) {
|
||||
stop = lhs_len + stop;
|
||||
// CPython returns empty string in such case
|
||||
if (stop < 0) {
|
||||
stop = start;
|
||||
}
|
||||
} else if (stop > lhs_len) {
|
||||
stop = lhs_len;
|
||||
machine_uint_t start, stop;
|
||||
if (!m_seq_get_fast_slice_indexes(lhs_len, rhs_in, &start, &stop)) {
|
||||
assert(0);
|
||||
}
|
||||
return mp_obj_new_str(lhs_data + start, stop - start, false);
|
||||
#endif
|
||||
@ -187,6 +171,18 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data);
|
||||
return mp_obj_str_builder_end(s);
|
||||
}
|
||||
|
||||
// These 2 are never passed here, dealt with as a special case in rt_binary_op().
|
||||
//case RT_BINARY_OP_EQUAL:
|
||||
//case RT_BINARY_OP_NOT_EQUAL:
|
||||
case RT_BINARY_OP_LESS:
|
||||
case RT_BINARY_OP_LESS_EQUAL:
|
||||
case RT_BINARY_OP_MORE:
|
||||
case RT_BINARY_OP_MORE_EQUAL:
|
||||
if (MP_OBJ_IS_STR(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));
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
@ -87,7 +88,17 @@ static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
switch (op) {
|
||||
case RT_BINARY_OP_SUBSCR:
|
||||
{
|
||||
// tuple load
|
||||
#if MICROPY_ENABLE_SLICE
|
||||
if (MP_OBJ_IS_TYPE(rhs, &slice_type)) {
|
||||
machine_uint_t start, stop;
|
||||
if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) {
|
||||
assert(0);
|
||||
}
|
||||
mp_obj_tuple_t *res = mp_obj_new_tuple(stop - start, NULL);
|
||||
m_seq_copy(res->items, o->items + start, res->len, mp_obj_t);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
uint index = mp_get_index(o->base.type, o->len, rhs);
|
||||
return o->items[index];
|
||||
}
|
||||
|
26
py/runtime.c
26
py/runtime.c
@ -768,8 +768,8 @@ mp_obj_t rt_store_set(mp_obj_t set, mp_obj_t item) {
|
||||
|
||||
// unpacked items are stored in reverse order into the array pointed to by items
|
||||
void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) {
|
||||
uint seq_len;
|
||||
if (MP_OBJ_IS_TYPE(seq_in, &tuple_type) || MP_OBJ_IS_TYPE(seq_in, &list_type)) {
|
||||
uint seq_len;
|
||||
mp_obj_t *seq_items;
|
||||
if (MP_OBJ_IS_TYPE(seq_in, &tuple_type)) {
|
||||
mp_obj_tuple_get(seq_in, &seq_len, &seq_items);
|
||||
@ -777,17 +777,33 @@ void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) {
|
||||
mp_obj_list_get(seq_in, &seq_len, &seq_items);
|
||||
}
|
||||
if (seq_len < num) {
|
||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", (void*)(machine_uint_t)seq_len));
|
||||
goto too_short;
|
||||
} else if (seq_len > num) {
|
||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", (void*)(machine_uint_t)num));
|
||||
goto too_long;
|
||||
}
|
||||
for (uint i = 0; i < num; i++) {
|
||||
items[i] = seq_items[num - 1 - i];
|
||||
}
|
||||
} else {
|
||||
// TODO call rt_getiter and extract via rt_iternext
|
||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(seq_in)));
|
||||
mp_obj_t iterable = rt_getiter(seq_in);
|
||||
|
||||
for (seq_len = 0; seq_len < num; seq_len++) {
|
||||
mp_obj_t el = rt_iternext(iterable);
|
||||
if (el == mp_const_stop_iteration) {
|
||||
goto too_short;
|
||||
}
|
||||
items[num - 1 - seq_len] = el;
|
||||
}
|
||||
if (rt_iternext(iterable) != mp_const_stop_iteration) {
|
||||
goto too_long;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
too_short:
|
||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", seq_len));
|
||||
too_long:
|
||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", num));
|
||||
}
|
||||
|
||||
mp_obj_t rt_build_map(int n_args) {
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
// Helpers for sequence types
|
||||
|
||||
#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
|
||||
|
||||
// Implements backend of sequence * integer operation. Assumes elements are
|
||||
// memory-adjacent in sequence.
|
||||
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) {
|
||||
@ -23,3 +25,69 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void
|
||||
dest = (char*)dest + copy_sz;
|
||||
}
|
||||
}
|
||||
|
||||
bool m_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;
|
||||
}
|
||||
|
||||
// Unlike subscription, out-of-bounds slice indexes are never error
|
||||
if (start < 0) {
|
||||
start = len + start;
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
} else if (start > len) {
|
||||
start = len;
|
||||
}
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Special-case comparison function for sequences of bytes
|
||||
// Don't pass RT_BINARY_OP_NOT_EQUAL here
|
||||
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
|
||||
// Let's deal only with > & >=
|
||||
if (op == RT_BINARY_OP_LESS || op == RT_BINARY_OP_LESS_EQUAL) {
|
||||
SWAP(const byte*, data1, data2);
|
||||
SWAP(uint, len1, len2);
|
||||
if (op == RT_BINARY_OP_LESS) {
|
||||
op = RT_BINARY_OP_MORE;
|
||||
} else {
|
||||
op = RT_BINARY_OP_MORE_EQUAL;
|
||||
}
|
||||
}
|
||||
uint min_len = len1 < len2 ? len1 : len2;
|
||||
int res = memcmp(data1, data2, min_len);
|
||||
if (res < 0) {
|
||||
return false;
|
||||
}
|
||||
if (res > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we had tie in the last element...
|
||||
// ... and we have lists of different lengths...
|
||||
if (len1 != len2) {
|
||||
if (len1 < len2) {
|
||||
// ... then longer list length wins (we deal only with >)
|
||||
return false;
|
||||
}
|
||||
} else if (op == RT_BINARY_OP_MORE) {
|
||||
// Otherwise, if we have strict relation, equality means failure
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -16,3 +16,7 @@ print(x)
|
||||
|
||||
x += [2, 1]
|
||||
print(x)
|
||||
|
||||
print(x[1:])
|
||||
print(x[:-1])
|
||||
print(x[2:3])
|
||||
|
36
tests/basics/seq-unpack.py
Normal file
36
tests/basics/seq-unpack.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Basics
|
||||
a, b = 1, 2
|
||||
print(a, b)
|
||||
a, b = (1, 2)
|
||||
print(a, b)
|
||||
(a, b) = 1, 2
|
||||
print(a, b)
|
||||
(a, b) = (1, 2)
|
||||
print(a, b)
|
||||
|
||||
# Tuples/lists are optimized
|
||||
a, b = [1, 2]
|
||||
print(a, b)
|
||||
[a, b] = 100, 200
|
||||
print(a, b)
|
||||
|
||||
try:
|
||||
a, b, c = (1, 2)
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
try:
|
||||
a, b, c = [1, 2, 3, 4]
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
|
||||
# Generic iterable object
|
||||
a, b, c = range(3)
|
||||
print(a, b, c)
|
||||
try:
|
||||
a, b, c = range(2)
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
try:
|
||||
a, b, c = range(4)
|
||||
except ValueError:
|
||||
print("ValueError")
|
50
tests/basics/string-compare.py
Normal file
50
tests/basics/string-compare.py
Normal file
@ -0,0 +1,50 @@
|
||||
print("" == "")
|
||||
print("" > "")
|
||||
print("" < "")
|
||||
print("" == "1")
|
||||
print("1" == "")
|
||||
print("" > "1")
|
||||
print("1" > "")
|
||||
print("" < "1")
|
||||
print("1" < "")
|
||||
print("" >= "1")
|
||||
print("1" >= "")
|
||||
print("" <= "1")
|
||||
print("1" <= "")
|
||||
|
||||
print("1" == "1")
|
||||
print("1" != "1")
|
||||
print("1" == "2")
|
||||
print("1" == "10")
|
||||
|
||||
print("1" > "1")
|
||||
print("1" > "2")
|
||||
print("2" > "1")
|
||||
print("10" > "1")
|
||||
print("1/" > "1")
|
||||
print("1" > "10")
|
||||
print("1" > "1/")
|
||||
|
||||
print("1" < "1")
|
||||
print("2" < "1")
|
||||
print("1" < "2")
|
||||
print("1" < "10")
|
||||
print("1" < "1/")
|
||||
print("10" < "1")
|
||||
print("1/" < "1")
|
||||
|
||||
print("1" >= "1")
|
||||
print("1" >= "2")
|
||||
print("2" >= "1")
|
||||
print("10" >= "1")
|
||||
print("1/" >= "1")
|
||||
print("1" >= "10")
|
||||
print("1" >= "1/")
|
||||
|
||||
print("1" <= "1")
|
||||
print("2" <= "1")
|
||||
print("1" <= "2")
|
||||
print("1" <= "10")
|
||||
print("1" <= "1/")
|
||||
print("10" <= "1")
|
||||
print("1/" <= "1")
|
16
tests/basics/tuple1.py
Normal file
16
tests/basics/tuple1.py
Normal file
@ -0,0 +1,16 @@
|
||||
# basic tuple functionality
|
||||
x = (1, 2, 3 * 4)
|
||||
print(x)
|
||||
try:
|
||||
x[0] = 4
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
print(x)
|
||||
try:
|
||||
x.append(5)
|
||||
except AttributeError:
|
||||
print("AttributeError")
|
||||
|
||||
print(x[1:])
|
||||
print(x[:-1])
|
||||
print(x[2:3])
|
@ -14,6 +14,10 @@ include ../py/py.mk
|
||||
CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -DUNIX $(CFLAGS_MOD)
|
||||
LDFLAGS = $(LDFLAGS_MOD) -lm
|
||||
|
||||
ifeq ($(MICROPY_MOD_TIME),1)
|
||||
CFLAGS_MOD += -DMICROPY_MOD_TIME=1
|
||||
SRC_MOD += time.c
|
||||
endif
|
||||
ifeq ($(MICROPY_MOD_FFI),1)
|
||||
CFLAGS_MOD += `pkg-config --cflags libffi` -DMICROPY_MOD_FFI=1
|
||||
LDFLAGS_MOD += -ldl -lffi
|
||||
|
@ -24,6 +24,7 @@
|
||||
extern const mp_obj_fun_native_t mp_builtin_open_obj;
|
||||
void file_init();
|
||||
void rawsocket_init();
|
||||
void time_init();
|
||||
void ffi_init();
|
||||
|
||||
static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
|
||||
@ -242,6 +243,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
file_init();
|
||||
rawsocket_init();
|
||||
#if MICROPY_MOD_TIME
|
||||
time_init();
|
||||
#endif
|
||||
#if MICROPY_MOD_FFI
|
||||
ffi_init();
|
||||
#endif
|
||||
|
@ -1,4 +1,7 @@
|
||||
# Enable/disable modules to be included in interpreter
|
||||
|
||||
# Subset of CPython time module
|
||||
MICROPY_MOD_TIME = 1
|
||||
|
||||
# ffi module requires libffi (libffi-dev Debian package)
|
||||
MICROPY_MOD_FFI = 0
|
||||
|
30
unix/time.c
Normal file
30
unix/time.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
static mp_obj_t mod_time_time() {
|
||||
return mp_obj_new_int((machine_int_t)time(NULL));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time);
|
||||
|
||||
// Note: this is deprecated since CPy3.3, but pystone still uses it.
|
||||
static mp_obj_t mod_time_clock() {
|
||||
// return mp_obj_new_int((machine_int_t)clock());
|
||||
// POSIX requires CLOCKS_PER_SEC equals 1000000, so that's what we assume
|
||||
// float cannot represent full range of int32 precisely, so we pre-divide
|
||||
// int to reduce resolution, and then actually do float division hoping
|
||||
// to preserve integer part resolution.
|
||||
return mp_obj_new_float((float)(clock() / 1000) / 1000.0);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock);
|
||||
|
||||
void time_init() {
|
||||
mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("time"));
|
||||
rt_store_attr(m, QSTR_FROM_STR_STATIC("time"), (mp_obj_t)&mod_time_time_obj);
|
||||
rt_store_attr(m, QSTR_FROM_STR_STATIC("clock"), (mp_obj_t)&mod_time_clock_obj);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user