diff options
author | John R. Lenton <jlenton@gmail.com> | 2014-01-13 00:41:12 +0000 |
---|---|---|
committer | John R. Lenton <jlenton@gmail.com> | 2014-01-13 00:41:12 +0000 |
commit | 13e64f06604c1502317921201bdde33c57161808 (patch) | |
tree | 865c85e4aaa41fc86711010362b7c0b0b4dbf832 | |
parent | 813edf63a3e4c0bab3dd5edd4e7295462386c2f3 (diff) | |
parent | 34f813ee29c7191e3de455c3fc9c788496e3b29e (diff) | |
download | micropython-13e64f06604c1502317921201bdde33c57161808.tar.gz micropython-13e64f06604c1502317921201bdde33c57161808.zip |
Merge remote-tracking branch 'upstream/master' into containment
64 files changed, 1632 insertions, 249 deletions
diff --git a/.gitignore b/.gitignore index 95be7bf651..6224e57cdb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ ###################### *.swp +# Build directory +###################### +build/ diff --git a/logo/micropythonpowered-art.png b/logo/micropythonpowered-art.png Binary files differnew file mode 100644 index 0000000000..9045bb0a43 --- /dev/null +++ b/logo/micropythonpowered-art.png diff --git a/logo/vector-logo-2.png b/logo/vector-logo-2.png Binary files differindex 3ad2383ff5..72ce88e1d5 100644 --- a/logo/vector-logo-2.png +++ b/logo/vector-logo-2.png diff --git a/logo/vector-logo-inkscape_master.svg b/logo/vector-logo-inkscape_master.svg index 19415d41b7..bbfca47803 100644 --- a/logo/vector-logo-inkscape_master.svg +++ b/logo/vector-logo-inkscape_master.svg @@ -32,13 +32,13 @@ inkscape:window-height="1086" id="namedview127" showgrid="false" - inkscape:zoom="1.1668212" - inkscape:cx="347.36024" - inkscape:cy="357.11268" + inkscape:zoom="5.4082024" + inkscape:cx="367.53099" + inkscape:cy="675.33912" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="0" - inkscape:current-layer="layer6" /> + inkscape:current-layer="layer4" /> <defs id="defs4"> <linearGradient @@ -693,6 +693,12 @@ d="m 197.35296,637.05028 26.22631,-36.06117 193.41902,1.96697 -36.06117,45.24038 -89.82511,-9.83486 7.21224,-15.08013 -43.27341,3.93395 z" id="path5039" inkscape:connector-curvature="0" /> + <path + style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" + d="m 344.52579,102.27483 15.42653,-40.280383 23.99682,-15.426528 17.14059,9.427323 3.42812,11.998411 28.28197,-6.856235 14.56949,21.425734 0.85703,38.566318 -13.71247,30.85306 -21.42573,9.42732 -20.5687,-12.85544 -20.56871,8.57029 -24.98883,-23.71207 z" + id="path3253" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccccccc" /> </g> <g inkscape:groupmode="layer" diff --git a/py/compile.c b/py/compile.c index 2e22d64262..b948f7aa47 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1316,7 +1316,7 @@ void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { int l_end = comp_next_label(comp); c_if_cond(comp, pns->nodes[0], true, l_end); - EMIT(load_id, MP_QSTR_AssertionError); + EMIT(load_global, MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { // assertion message compile_node(comp, pns->nodes[1]); diff --git a/py/emitpass1.c b/py/emitpass1.c index 2f0ecac86d..60fdd0b825 100644 --- a/py/emitpass1.c +++ b/py/emitpass1.c @@ -45,10 +45,7 @@ static void emit_pass1_load_id(emit_t *emit, qstr qstr) { bool added; id_info_t *id = scope_find_or_add_id(emit->scope, qstr, &added); if (added) { - if (qstr == MP_QSTR_AssertionError) { - // TODO how much of a hack is this? - id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; - } else if (strcmp(qstr_str(qstr), "super") == 0 && emit->scope->kind == SCOPE_FUNCTION) { + if (strcmp(qstr_str(qstr), "super") == 0 && emit->scope->kind == SCOPE_FUNCTION) { // special case, super is a global, and also counts as use of __class__ id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; id_info_t *id2 = scope_find_local_in_parent(emit->scope, emit->qstr___class__); @@ -8,15 +8,8 @@ #if MICROPY_ENABLE_GC -// a machine word is big enough to hold a pointer -/* -#define BYTES_PER_WORD (8) -typedef unsigned long machine_uint_t; -*/ typedef unsigned char byte; -#define BITS_PER_BYTE (8) -#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) #define WORDS_PER_BLOCK (4) #define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD) #define STACK_SIZE (64) // tunable; minimum is 1 diff --git a/py/lexer.c b/py/lexer.c index d4205236c3..f7f9c631f3 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -299,8 +299,15 @@ static void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs // backslash (outside string literals) must appear just before a physical newline next_char(lex); if (!is_physical_newline(lex)) { - // TODO SyntaxError - assert(0); + // SyntaxError: unexpected character after line continuation character + tok->src_name = lex->name; + tok->src_line = lex->line; + tok->src_column = lex->column; + tok->kind = MP_TOKEN_BAD_LINE_CONTINUATION; + vstr_reset(&lex->vstr); + tok->str = vstr_str(&lex->vstr); + tok->len = 0; + return; } else { next_char(lex); } diff --git a/py/lexer.h b/py/lexer.h index 9dfcb128c5..428ff03c5b 100644 --- a/py/lexer.h +++ b/py/lexer.h @@ -10,19 +10,20 @@ typedef enum _mp_token_kind_t { MP_TOKEN_INVALID, MP_TOKEN_DEDENT_MISMATCH, MP_TOKEN_LONELY_STRING_OPEN, + MP_TOKEN_BAD_LINE_CONTINUATION, - MP_TOKEN_NEWLINE, // 4 - MP_TOKEN_INDENT, // 5 - MP_TOKEN_DEDENT, // 6 + MP_TOKEN_NEWLINE, // 5 + MP_TOKEN_INDENT, // 6 + MP_TOKEN_DEDENT, // 7 - MP_TOKEN_NAME, // 7 + MP_TOKEN_NAME, // 8 MP_TOKEN_NUMBER, MP_TOKEN_STRING, MP_TOKEN_BYTES, MP_TOKEN_ELLIPSIS, - MP_TOKEN_KW_FALSE, // 12 + MP_TOKEN_KW_FALSE, // 13 MP_TOKEN_KW_NONE, MP_TOKEN_KW_TRUE, MP_TOKEN_KW_AND, @@ -31,7 +32,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_KW_BREAK, MP_TOKEN_KW_CLASS, MP_TOKEN_KW_CONTINUE, - MP_TOKEN_KW_DEF, // 21 + MP_TOKEN_KW_DEF, // 22 MP_TOKEN_KW_DEL, MP_TOKEN_KW_ELIF, MP_TOKEN_KW_ELSE, @@ -41,7 +42,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_KW_FROM, MP_TOKEN_KW_GLOBAL, MP_TOKEN_KW_IF, - MP_TOKEN_KW_IMPORT, // 31 + MP_TOKEN_KW_IMPORT, // 32 MP_TOKEN_KW_IN, MP_TOKEN_KW_IS, MP_TOKEN_KW_LAMBDA, @@ -51,12 +52,12 @@ typedef enum _mp_token_kind_t { MP_TOKEN_KW_PASS, MP_TOKEN_KW_RAISE, MP_TOKEN_KW_RETURN, - MP_TOKEN_KW_TRY, // 41 + MP_TOKEN_KW_TRY, // 42 MP_TOKEN_KW_WHILE, MP_TOKEN_KW_WITH, MP_TOKEN_KW_YIELD, - MP_TOKEN_OP_PLUS, // 45 + MP_TOKEN_OP_PLUS, // 46 MP_TOKEN_OP_MINUS, MP_TOKEN_OP_STAR, MP_TOKEN_OP_DBL_STAR, @@ -66,7 +67,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_OP_LESS, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_OP_MORE, - MP_TOKEN_OP_DBL_MORE, // 55 + MP_TOKEN_OP_DBL_MORE, // 56 MP_TOKEN_OP_AMPERSAND, MP_TOKEN_OP_PIPE, MP_TOKEN_OP_CARET, @@ -76,7 +77,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_OP_DBL_EQUAL, MP_TOKEN_OP_NOT_EQUAL, - MP_TOKEN_DEL_PAREN_OPEN, // 64 + MP_TOKEN_DEL_PAREN_OPEN, // 65 MP_TOKEN_DEL_PAREN_CLOSE, MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE, @@ -86,7 +87,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_PERIOD, MP_TOKEN_DEL_SEMICOLON, - MP_TOKEN_DEL_AT, // 74 + MP_TOKEN_DEL_AT, // 75 MP_TOKEN_DEL_EQUAL, MP_TOKEN_DEL_PLUS_EQUAL, MP_TOKEN_DEL_MINUS_EQUAL, @@ -96,7 +97,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_DEL_PERCENT_EQUAL, MP_TOKEN_DEL_AMPERSAND_EQUAL, MP_TOKEN_DEL_PIPE_EQUAL, - MP_TOKEN_DEL_CARET_EQUAL, // 84 + MP_TOKEN_DEL_CARET_EQUAL, // 85 MP_TOKEN_DEL_DBL_MORE_EQUAL, MP_TOKEN_DEL_DBL_LESS_EQUAL, MP_TOKEN_DEL_DBL_STAR_EQUAL, @@ -132,28 +132,45 @@ void mp_set_init(mp_set_t *set, int n) { set->table = m_new0(mp_obj_t, set->alloc); } -mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found) { - int hash = mp_obj_hash(index); - assert(set->alloc); /* FIXME: if alloc is ever 0 when doing a lookup, this'll fail: */ - int pos = hash % set->alloc; +static void mp_set_rehash(mp_set_t *set) { + int old_alloc = set->alloc; + mp_obj_t *old_table = set->table; + set->alloc = get_doubling_prime_greater_or_equal_to(set->alloc + 1); + set->used = 0; + set->table = m_new0(mp_obj_t, set->alloc); + for (int i = 0; i < old_alloc; i++) { + if (old_table[i] != NULL) { + mp_set_lookup(set, old_table[i], true); + } + } + m_del(mp_obj_t, old_table, old_alloc); +} + +mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { + int hash; + int pos; + if (set->alloc == 0) { + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + mp_set_rehash(set); + } else { + return NULL; + } + } + if (lookup_kind & MP_MAP_LOOKUP_FIRST) { + hash = 0; + pos = 0; + } else { + hash = mp_obj_hash(index);; + pos = hash % set->alloc; + } for (;;) { mp_obj_t elem = set->table[pos]; if (elem == MP_OBJ_NULL) { // not in table - if (add_if_not_found) { + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { if (set->used + 1 >= set->alloc) { // not enough room in table, rehash it - int old_alloc = set->alloc; - mp_obj_t *old_table = set->table; - set->alloc = get_doubling_prime_greater_or_equal_to(set->alloc + 1); - set->used = 0; - set->table = m_new(mp_obj_t, set->alloc); - for (int i = 0; i < old_alloc; i++) { - if (old_table[i] != NULL) { - mp_set_lookup(set, old_table[i], true); - } - } - m_del(mp_obj_t, old_table, old_alloc); + mp_set_rehash(set); // restart the search for the new element pos = hash % set->alloc; } else { @@ -161,11 +178,17 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found) { set->table[pos] = index; return index; } + } else if (lookup_kind & MP_MAP_LOOKUP_FIRST) { + pos++; } else { return MP_OBJ_NULL; } - } else if (mp_obj_equal(elem, index)) { + } else if (lookup_kind & MP_MAP_LOOKUP_FIRST || mp_obj_equal(elem, index)) { // found it + if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { + set->used--; + set->table[pos] = NULL; + } return elem; } else { // not yet found, keep searching in this table @@ -173,3 +196,13 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found) { } } } + +void mp_set_clear(mp_set_t *set) { + set->used = 0; + machine_uint_t a = set->alloc; + set->alloc = 0; + set->table = m_renew(mp_obj_t, set->table, a, set->alloc); + for (uint i=0; i<set->alloc; i++) { + set->table[i] = NULL; + } +} @@ -19,9 +19,10 @@ typedef struct _mp_set_t { } mp_set_t; typedef enum _mp_map_lookup_kind_t { - MP_MAP_LOOKUP, - MP_MAP_LOOKUP_ADD_IF_NOT_FOUND, - MP_MAP_LOOKUP_REMOVE_IF_FOUND, + MP_MAP_LOOKUP, // 0 + MP_MAP_LOOKUP_ADD_IF_NOT_FOUND, // 1 + MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2 + MP_MAP_LOOKUP_FIRST = 4, } mp_map_lookup_kind_t; int get_doubling_prime_greater_or_equal_to(int x); @@ -31,4 +32,5 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t void mp_map_clear(mp_map_t *map); void mp_set_init(mp_set_t *set, int n); -mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found); +mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); +void mp_set_clear(mp_set_t *set); diff --git a/py/mpconfig.h b/py/mpconfig.h index 2017ba366a..ada4aa2ea4 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -62,6 +62,18 @@ #define MICROPY_ENABLE_LEXER_UNIX (0) #endif +// Long int implementation +#define MICROPY_LONGINT_IMPL_NONE (0) +#define MICROPY_LONGINT_IMPL_LONGLONG (1) + +#ifndef MICROPY_LONGINT_IMPL +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG +typedef long long mp_longint_impl_t; +#endif + // Whether to support float and complex types #ifndef MICROPY_ENABLE_FLOAT #define MICROPY_ENABLE_FLOAT (0) @@ -76,6 +88,11 @@ /*****************************************************************************/ /* Miscellaneous settings */ +#define BITS_PER_BYTE (8) +#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) +// machine_int_t value with most significant bit set +#define WORD_MSBIT_HIGH (1 << (BYTES_PER_WORD * 8 - 1)) + // printf format spec to use for machine_int_t and friends #ifndef INT_FMT #ifdef __LP64__ @@ -117,6 +117,13 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } else if (MP_OBJ_IS_TYPE(o1, &str_type) && MP_OBJ_IS_TYPE(o2, &str_type)) { return mp_obj_str_get(o1) == mp_obj_str_get(o2); } else { + mp_obj_base_t *o = o1; + if (o->type->binary_op != NULL) { + mp_obj_t r = o->type->binary_op(RT_COMPARE_OP_EQUAL, o1, o2); + if (r != MP_OBJ_NULL) { + return r == mp_const_true ? true : false; + } + } // TODO: Debugging helper printf("Equality for '%s' and '%s' types not yet implemented\n", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2)); assert(0); @@ -231,7 +238,7 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index) } } -// may return NULL +// may return MP_OBJ_NULL mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { mp_small_int_t len = 0; if (MP_OBJ_IS_TYPE(o_in, &str_type)) { @@ -249,7 +256,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { } else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) { len = mp_obj_dict_len(o_in); } else { - return NULL; + return MP_OBJ_NULL; } return MP_OBJ_NEW_SMALL_INT(len); } @@ -34,6 +34,8 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // - xxxx...xx10: a qstr, bits 2 and above are the value // - xxxx...xx00: a pointer to an mp_obj_base_t +// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range +#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) #define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0) #define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2) #define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0) @@ -59,6 +61,15 @@ typedef struct _mp_obj_base_t mp_obj_base_t; #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, n_args_max, (mp_fun_var_t)fun_name) #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, 0, (~((machine_uint_t)0)), (mp_fun_kw_t)fun_name) +// These macros are used to declare and define constant staticmethond and classmethod objects +// You can put "static" in front of the definitions to make them local + +#define MP_DECLARE_CONST_STATICMETHOD_OBJ(obj_name) extern const mp_obj_staticmethod_t obj_name +#define MP_DECLARE_CONST_CLASSMETHOD_OBJ(obj_name) extern const mp_obj_classmethod_t obj_name + +#define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_obj_staticmethod_t obj_name = {{&mp_type_staticmethod}, fun_name} +#define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_obj_classmethod_t obj_name = {{&mp_type_classmethod}, fun_name} + // Need to declare this here so we are not dependent on map.h struct _mp_map_t; struct _mp_map_elem_t; @@ -187,6 +198,8 @@ mp_obj_t mp_obj_new_none(void); mp_obj_t mp_obj_new_bool(bool value); mp_obj_t mp_obj_new_cell(mp_obj_t obj); mp_obj_t mp_obj_new_int(machine_int_t value); +mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value); +mp_obj_t mp_obj_new_int_from_long_str(const char *s); mp_obj_t mp_obj_new_str(qstr qstr); #if MICROPY_ENABLE_FLOAT mp_obj_t mp_obj_new_float(mp_float_t val); @@ -316,3 +329,18 @@ extern const mp_obj_type_t gen_instance_type; extern const mp_obj_type_t module_type; mp_obj_t mp_obj_new_module(qstr module_name); struct _mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in); + +// staticmethod and classmethod types; defined here so we can make const versions + +extern const mp_obj_type_t mp_type_staticmethod; +extern const mp_obj_type_t mp_type_classmethod; + +typedef struct _mp_obj_staticmethod_t { + mp_obj_base_t base; + mp_obj_t fun; +} mp_obj_staticmethod_t; + +typedef struct _mp_obj_classmethod_t { + mp_obj_base_t base; + mp_obj_t fun; +} mp_obj_classmethod_t; diff --git a/py/objdict.c b/py/objdict.c index 5f8a04d05e..e164ed74ca 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -145,6 +145,35 @@ static mp_obj_t dict_copy(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy); +// this is a classmethod +static mp_obj_t dict_fromkeys(int n_args, const mp_obj_t *args) { + assert(2 <= n_args && n_args <= 3); + mp_obj_t iter = rt_getiter(args[1]); + mp_obj_t len = mp_obj_len_maybe(iter); + mp_obj_t value = mp_const_none; + mp_obj_t next = NULL; + mp_obj_dict_t *self = NULL; + + if (n_args > 2) { + value = args[2]; + } + + if (len == MP_OBJ_NULL) { + /* object's type doesn't have a __len__ slot */ + self = mp_obj_new_dict(0); + } else { + self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len)); + } + + while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { + mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + } + + return self; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys); +static MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, (const mp_obj_t)&dict_fromkeys_fun_obj); + static mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp_map_lookup_kind_t lookup_kind) { mp_map_elem_t *elem = mp_map_lookup(self, key, lookup_kind); mp_obj_t value; @@ -286,23 +315,18 @@ static mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { if (next != NULL) { switch (self->kind) { - case MP_DICT_VIEW_ITEMS: - { - mp_obj_t items[] = {next->key, next->value}; - return mp_obj_new_tuple(2, items); - } - case MP_DICT_VIEW_KEYS: - { - return next->key; - } - case MP_DICT_VIEW_VALUES: - { - return next->value; - } - default: - { - assert(0); /* can't happen */ - } + case MP_DICT_VIEW_ITEMS: + { + mp_obj_t items[] = {next->key, next->value}; + return mp_obj_new_tuple(2, items); + } + case MP_DICT_VIEW_KEYS: + return next->key; + case MP_DICT_VIEW_VALUES: + return next->value; + default: + assert(0); /* can't happen */ + return mp_const_none; } } else { return mp_const_stop_iteration; @@ -326,7 +350,6 @@ static mp_obj_t dict_view_getiter(mp_obj_t view_in) { return o; } - static void dict_view_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); mp_obj_dict_view_t *self = self_in; @@ -370,7 +393,6 @@ mp_obj_t mp_obj_new_dict_view(mp_obj_dict_t *dict, mp_dict_view_kind_t kind) { return o; } - static mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { assert(MP_OBJ_IS_TYPE(self_in, &dict_type)); mp_obj_dict_t *self = self_in; @@ -392,67 +414,13 @@ static mp_obj_t dict_values(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); - -/******************************************************************************/ -/* dict metaclass */ - -static mp_obj_t dict_fromkeys(int n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 3); - mp_obj_t iter = rt_getiter(args[1]); - mp_obj_t len = mp_obj_len_maybe(iter); - mp_obj_t value = mp_const_none; - mp_obj_t next = NULL; - mp_obj_dict_t *self = NULL; - - if (n_args > 2) { - value = args[2]; - } - - if (len == NULL) { - /* object's type doesn't have a __len__ slot */ - self = mp_obj_new_dict(0); - } else { - self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len)); - } - - while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { - mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; - } - - return self; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_obj, 2, 3, dict_fromkeys); - -static const mp_method_t dict_class_methods[] = { - { "fromkeys", &dict_fromkeys_obj }, - { NULL, NULL }, // end-of-list sentinel -}; - -/* this should be unnecessary when inheritance works */ -static void dict_class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { - print(env, "<class 'dict'>"); -} - -/* this should be unnecessary when inheritance works */ -static mp_obj_t dict_class_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) { - return rt_build_map(0); -} - -static const mp_obj_type_t dict_class = { - { &mp_const_type }, - "dict_class", - .print = dict_class_print, - .methods = dict_class_methods, - .call_n = dict_class_call_n, -}; - - /******************************************************************************/ -/* dict constructors & etc */ +/* dict constructors & public C API */ static const mp_method_t dict_type_methods[] = { { "clear", &dict_clear_obj }, { "copy", &dict_copy_obj }, + { "fromkeys", &dict_fromkeys_obj }, { "get", &dict_get_obj }, { "items", &dict_items_obj }, { "keys", &dict_keys_obj }, @@ -465,7 +433,7 @@ static const mp_method_t dict_type_methods[] = { }; const mp_obj_type_t dict_type = { - { &dict_class }, + { &mp_const_type }, "dict", .print = dict_print, .make_new = dict_make_new, diff --git a/py/objint.c b/py/objint.c index 9cd5ebae29..26d3c0e337 100644 --- a/py/objint.c +++ b/py/objint.c @@ -11,8 +11,16 @@ typedef struct _mp_obj_int_t { mp_obj_base_t base; +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + mp_longint_impl_t val; +#endif } mp_obj_int_t; +void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in); +mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); + +// This dispatcher function is expected to be independent of the implementation +// of long int static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) { switch (n_args) { case 0: @@ -20,7 +28,7 @@ static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) case 1: // TODO allow string as arg and parse it - return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0])); + return mp_obj_new_int(mp_obj_get_int(args[0])); //case 2: // TODO, parse with given base @@ -33,9 +41,41 @@ static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) const mp_obj_type_t int_type = { { &mp_const_type }, "int", + .print = int_print, .make_new = int_make_new, + .binary_op = int_binary_op, }; +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE +// This is called only for non-SMALL_INT +void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { +} + +// This is called only for non-SMALL_INT +mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + assert(0); +} + +// This is called only with strings whose value doesn't fit in SMALL_INT +mp_obj_t mp_obj_new_int_from_long_str(const char *s) { + assert(0); +} + +mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) { + // SMALL_INT accepts only signed numbers, of one bit less size + // then word size, which totals 2 bits less for unsigned numbers. + if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) { + return MP_OBJ_NEW_SMALL_INT(value); + } + // TODO: Raise exception + assert(0); +} + mp_obj_t mp_obj_new_int(machine_int_t value) { - return MP_OBJ_NEW_SMALL_INT(value); + if (MP_OBJ_FITS_SMALL_INT(value)) { + return MP_OBJ_NEW_SMALL_INT(value); + } + // TODO: Raise exception + assert(0); } +#endif diff --git a/py/objlist.c b/py/objlist.c index 7d0402d286..fa8ec67d09 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -21,6 +21,7 @@ typedef struct _mp_obj_list_t { static mp_obj_t mp_obj_new_list_iterator(mp_obj_list_t *list, int cur); static mp_obj_list_t *list_new(uint n); +static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in); /******************************************************************************/ /* list */ @@ -61,6 +62,61 @@ static mp_obj_t list_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args return NULL; } +// Don't pass RT_COMPARE_OP_NOT_EQUAL here +static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { + assert(MP_OBJ_IS_TYPE(self_in, &list_type)); + if (!MP_OBJ_IS_TYPE(another_in, &list_type)) { + return false; + } + mp_obj_list_t *self = self_in; + mp_obj_list_t *another = another_in; + if (op == RT_COMPARE_OP_EQUAL && self->len != another->len) { + return false; + } + + // Let's deal only with > & >= + if (op == RT_COMPARE_OP_LESS || op == RT_COMPARE_OP_LESS_EQUAL) { + mp_obj_t t = self; + self = another; + another = t; + if (op == RT_COMPARE_OP_LESS) { + op = RT_COMPARE_OP_MORE; + } else { + op = RT_COMPARE_OP_MORE_EQUAL; + } + } + + int len = self->len < another->len ? self->len : another->len; + bool eq_status = true; // empty lists are equal + bool rel_status; + for (int i = 0; i < len; i++) { + eq_status = mp_obj_equal(self->items[i], another->items[i]); + if (op == RT_COMPARE_OP_EQUAL && !eq_status) { + return false; + } + rel_status = (rt_binary_op(op, self->items[i], another->items[i]) == mp_const_true); + if (!eq_status && !rel_status) { + return false; + } + } + + // If we had tie in the last element... + if (eq_status) { + // ... and we have lists of different lengths... + if (self->len != another->len) { + if (self->len < another->len) { + // ... then longer list length wins (we deal only with >) + return false; + } + } else if (op == RT_COMPARE_OP_MORE) { + // Otherwise, if we have strict relation, equality means failure + return false; + } + } + + return true; +} + static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = lhs; switch (op) { @@ -81,6 +137,14 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { memcpy(s->items + o->len, p->items, sizeof(mp_obj_t) * p->len); return s; } + case RT_BINARY_OP_INPLACE_ADD: + { + if (!MP_OBJ_IS_TYPE(rhs, &list_type)) { + return NULL; + } + list_extend(lhs, rhs); + return o; + } case RT_BINARY_OP_MULTIPLY: { if (!MP_OBJ_IS_SMALL_INT(rhs)) { @@ -96,6 +160,15 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } return s; } + case RT_COMPARE_OP_EQUAL: + case RT_COMPARE_OP_LESS: + case RT_COMPARE_OP_LESS_EQUAL: + case RT_COMPARE_OP_MORE: + case RT_COMPARE_OP_MORE_EQUAL: + return MP_BOOL(list_cmp_helper(op, lhs, rhs)); + case RT_COMPARE_OP_NOT_EQUAL: + return MP_BOOL(!list_cmp_helper(RT_COMPARE_OP_EQUAL, lhs, rhs)); + default: // op not supported return NULL; @@ -117,6 +190,23 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { return mp_const_none; // return None, as per CPython } +static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { + assert(MP_OBJ_IS_TYPE(self_in, &list_type)); + assert(MP_OBJ_IS_TYPE(arg_in, &list_type)); + mp_obj_list_t *self = self_in; + mp_obj_list_t *arg = arg_in; + + if (self->len + arg->len > self->alloc) { + // TODO: use alloc policy for "4" + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4); + self->alloc = self->len + arg->len + 4; + } + + memcpy(self->items + self->len, arg->items, sizeof(mp_obj_t) * arg->len); + self->len += arg->len; + return mp_const_none; // return None, as per CPython +} + static mp_obj_t list_pop(int n_args, const mp_obj_t *args) { assert(1 <= n_args && n_args <= 2); assert(MP_OBJ_IS_TYPE(args[0], &list_type)); @@ -281,6 +371,7 @@ static mp_obj_t list_reverse(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append); +static MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend); static MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear); static MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy); static MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count); @@ -296,6 +387,7 @@ static const mp_method_t list_type_methods[] = { { "clear", &list_clear_obj }, { "copy", &list_copy_obj }, { "count", &list_count_obj }, + { "extend", &list_extend_obj }, { "index", &list_index_obj }, { "insert", &list_insert_obj }, { "pop", &list_pop_obj }, diff --git a/py/objset.c b/py/objset.c index 71ed553350..43bb61083b 100644 --- a/py/objset.c +++ b/py/objset.c @@ -1,5 +1,6 @@ #include <stdlib.h> #include <stdint.h> +#include <string.h> #include <assert.h> #include "nlr.h" @@ -16,8 +17,20 @@ typedef struct _mp_obj_set_t { mp_set_t set; } mp_obj_set_t; +typedef struct _mp_obj_set_it_t { + mp_obj_base_t base; + mp_obj_set_t *set; + machine_uint_t cur; +} mp_obj_set_it_t; + +static mp_obj_t set_it_iternext(mp_obj_t self_in); + void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { mp_obj_set_t *self = self_in; + if (self->set.used == 0) { + print(env, "set()"); + return; + } bool first = true; print(env, "{"); for (int i = 0; i < self->set.alloc; i++) { @@ -73,12 +86,383 @@ static mp_obj_t set_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) } } +const mp_obj_type_t set_it_type = { + { &mp_const_type }, + "set_iterator", + .iternext = set_it_iternext, +}; + +static mp_obj_t set_it_iternext(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_it_type)); + mp_obj_set_it_t *self = self_in; + machine_uint_t max = self->set->set.alloc; + mp_obj_t *table = self->set->set.table; + + for (machine_uint_t i = self->cur; i < max; i++) { + if (table[i] != NULL) { + self->cur = i + 1; + return table[i]; + } + } + + return mp_const_stop_iteration; +} + +static mp_obj_t set_getiter(mp_obj_t set_in) { + mp_obj_set_it_t *o = m_new_obj(mp_obj_set_it_t); + o->base.type = &set_it_type; + o->set = (mp_obj_set_t *)set_in; + o->cur = 0; + return o; +} + + +/******************************************************************************/ +/* set methods */ + +static mp_obj_t set_add(mp_obj_t self_in, mp_obj_t item) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add); + +static mp_obj_t set_clear(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + + mp_set_clear(&self->set); + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear); + +static mp_obj_t set_copy(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + + mp_obj_set_t *other = m_new_obj(mp_obj_set_t); + other->base.type = &set_type; + mp_set_init(&other->set, self->set.alloc - 1); + other->set.used = self->set.used; + memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t)); + + return other; +} +static MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy); + +static mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard); + +static mp_obj_t set_diff_int(int n_args, const mp_obj_t *args, bool update) { + assert(n_args > 0); + assert(MP_OBJ_IS_TYPE(args[0], &set_type)); + mp_obj_set_t *self; + if (update) { + self = args[0]; + } else { + self = set_copy(args[0]); + } + + + for (int i = 1; i < n_args; i++) { + mp_obj_t other = args[i]; + if (self == other) { + set_clear(self); + } else { + mp_obj_t iter = rt_getiter(other); + mp_obj_t next; + while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { + set_discard(self, next); + } + } + } + + return self; +} + +static mp_obj_t set_diff(int n_args, const mp_obj_t *args) { + return set_diff_int(n_args, args, false); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_obj, 1, set_diff); + +static mp_obj_t set_diff_update(int n_args, const mp_obj_t *args) { + set_diff_int(n_args, args, true); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_update_obj, 1, set_diff_update); + +static mp_obj_t set_intersect_int(mp_obj_t self_in, mp_obj_t other, bool update) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + if (self_in == other) { + return update ? mp_const_none : set_copy(self_in); + } + + mp_obj_set_t *self = self_in; + mp_obj_set_t *out = mp_obj_new_set(0, NULL); + + mp_obj_t iter = rt_getiter(other); + mp_obj_t next; + while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { + if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) { + set_add(out, next); + } + } + + if (update) { + m_del(mp_obj_t, self->set.table, self->set.alloc); + self->set.alloc = out->set.alloc; + self->set.used = out->set.used; + self->set.table = out->set.table; + } + + return update ? mp_const_none : out; +} + +static mp_obj_t set_intersect(mp_obj_t self_in, mp_obj_t other) { + return set_intersect_int(self_in, other, false); +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_obj, set_intersect); + +static mp_obj_t set_intersect_update(mp_obj_t self_in, mp_obj_t other) { + return set_intersect_int(self_in, other, true); +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_update_obj, set_intersect_update); + +static mp_obj_t set_isdisjoint(mp_obj_t self_in, mp_obj_t other) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + + mp_obj_t iter = rt_getiter(other); + mp_obj_t next; + while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { + if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) { + return mp_const_false; + } + } + return mp_const_true; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_isdisjoint_obj, set_isdisjoint); + +static mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool proper) { + mp_obj_set_t *self; + bool cleanup_self = false; + if (MP_OBJ_IS_TYPE(self_in, &set_type)) { + self = self_in; + } else { + self = set_make_new(NULL, 1, &self_in); + cleanup_self = true; + } + + mp_obj_set_t *other; + bool cleanup_other = false; + if (MP_OBJ_IS_TYPE(other_in, &set_type)) { + other = other_in; + } else { + other = set_make_new(NULL, 1, &other_in); + cleanup_other = true; + } + bool out = true; + if (proper && self->set.used == other->set.used) { + out = false; + } else { + mp_obj_t iter = set_getiter(self); + mp_obj_t next; + while ((next = set_it_iternext(iter)) != mp_const_stop_iteration) { + if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) { + out = false; + break; + } + } + } + if (cleanup_self) { + set_clear(self); + } + if (cleanup_other) { + set_clear(other); + } + return MP_BOOL(out); +} +static mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(self_in, other_in, false); +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_issubset_obj, set_issubset); + +static mp_obj_t set_issubset_proper(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(self_in, other_in, true); +} + +static mp_obj_t set_issuperset(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(other_in, self_in, false); +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_issuperset_obj, set_issuperset); + +static mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(other_in, self_in, true); +} + +static mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + if (!MP_OBJ_IS_TYPE(other_in, &set_type)) { + return mp_const_false; + } + mp_obj_set_t *other = other_in; + if (self->set.used != other->set.used) { + return mp_const_false; + } + return set_issubset(self_in, other_in); +} + +static mp_obj_t set_pop(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + + if (self->set.used == 0) { + nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "pop from an empty set")); + } + mp_obj_t obj = mp_set_lookup(&self->set, NULL, + MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_FIRST); + return obj; +} +static MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop); + +static mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) { + nlr_jump(mp_obj_new_exception(MP_QSTR_KeyError)); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove); + +static mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = self_in; + mp_obj_t iter = rt_getiter(other_in); + mp_obj_t next; + while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { + mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update); + +static mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + self_in = set_copy(self_in); + set_symmetric_difference_update(self_in, other_in); + return self_in; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference); + +static void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) { + mp_obj_t iter = rt_getiter(other_in); + mp_obj_t next; + while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { + mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + } +} + +static mp_obj_t set_update(int n_args, const mp_obj_t *args) { + assert(n_args > 0); + assert(MP_OBJ_IS_TYPE(args[0], &set_type)); + + for (int i = 1; i < n_args; i++) { + set_update_int(args[0], args[i]); + } + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR(set_update_obj, 1, set_update); + +static mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) { + assert(MP_OBJ_IS_TYPE(self_in, &set_type)); + mp_obj_set_t *self = set_copy(self_in); + set_update_int(self, other_in); + return self; +} +static MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union); + + +static mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { + mp_obj_t args[] = {lhs, rhs}; + switch (op) { + case RT_BINARY_OP_OR: + return set_union(lhs, rhs); + case RT_BINARY_OP_XOR: + return set_symmetric_difference(lhs, rhs); + case RT_BINARY_OP_AND: + return set_intersect(lhs, rhs); + case RT_BINARY_OP_SUBTRACT: + return set_diff(2, args); + case RT_BINARY_OP_INPLACE_OR: + return set_union(lhs, rhs); + case RT_BINARY_OP_INPLACE_XOR: + return set_symmetric_difference(lhs, rhs); + case RT_BINARY_OP_INPLACE_AND: + return set_intersect(lhs, rhs); + case RT_BINARY_OP_INPLACE_SUBTRACT: + return set_diff(2, args); + case RT_COMPARE_OP_LESS: + return set_issubset_proper(lhs, rhs); + case RT_COMPARE_OP_MORE: + return set_issuperset_proper(lhs, rhs); + case RT_COMPARE_OP_EQUAL: + return set_equal(lhs, rhs); + case RT_COMPARE_OP_LESS_EQUAL: + return set_issubset(lhs, rhs); + case RT_COMPARE_OP_MORE_EQUAL: + return set_issuperset(lhs, rhs); + case RT_COMPARE_OP_NOT_EQUAL: + return MP_BOOL(set_equal(lhs, rhs) == mp_const_false); + default: + // op not supported + return NULL; + } +} + +/******************************************************************************/ +/* set constructors & public C API */ + + +static const mp_method_t set_type_methods[] = { + { "add", &set_add_obj }, + { "clear", &set_clear_obj }, + { "copy", &set_copy_obj }, + { "discard", &set_discard_obj }, + { "difference", &set_diff_obj }, + { "difference_update", &set_diff_update_obj }, + { "intersection", &set_intersect_obj }, + { "intersection_update", &set_intersect_update_obj }, + { "isdisjoint", &set_isdisjoint_obj }, + { "issubset", &set_issubset_obj }, + { "issuperset", &set_issuperset_obj }, + { "pop", &set_pop_obj }, + { "remove", &set_remove_obj }, + { "symmetric_difference", &set_symmetric_difference_obj }, + { "symmetric_difference_update", &set_symmetric_difference_update_obj }, + { "union", &set_union_obj }, + { "update", &set_update_obj }, + { NULL, NULL }, // end-of-list sentinel +}; + const mp_obj_type_t set_type = { { &mp_const_type }, "set", .print = set_print, .binary_op = set_binary_op, .make_new = set_make_new, + .binary_op = set_binary_op, + .getiter = set_getiter, + .methods = set_type_methods, }; mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) { @@ -86,7 +470,7 @@ mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) { o->base.type = &set_type; mp_set_init(&o->set, n_args); for (int i = 0; i < n_args; i++) { - mp_set_lookup(&o->set, items[i], true); + mp_set_lookup(&o->set, items[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } return o; } @@ -94,5 +478,5 @@ mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) { void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { assert(MP_OBJ_IS_TYPE(self_in, &set_type)); mp_obj_set_t *self = self_in; - mp_set_lookup(&self->set, item, true); + mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } diff --git a/py/objstr.c b/py/objstr.c index eb8b4c4be1..4151cf007b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -165,6 +165,43 @@ static bool chr_in_str(const char* const str, const size_t str_len, const char c return false; } +static mp_obj_t str_find(int n_args, const mp_obj_t *args) { + assert(2 <= n_args && n_args <= 4); + assert(MP_OBJ_IS_TYPE(args[0], &str_type)); + if (!MP_OBJ_IS_TYPE(args[1], &str_type)) { + nlr_jump(mp_obj_new_exception_msg_1_arg( + MP_QSTR_TypeError, + "Can't convert '%s' object to str implicitly", + mp_obj_get_type_str(args[1]))); + } + + const char* haystack = qstr_str(((mp_obj_str_t*)args[0])->qstr); + const char* needle = qstr_str(((mp_obj_str_t*)args[1])->qstr); + + ssize_t haystack_len = strlen(haystack); + ssize_t needle_len = strlen(needle); + + size_t start = 0; + size_t end = haystack_len; + /* TODO use a non-exception-throwing mp_get_index */ + if (n_args >= 3 && args[2] != mp_const_none) { + start = mp_get_index(&str_type, haystack_len, args[2]); + } + if (n_args >= 4 && args[3] != mp_const_none) { + end = mp_get_index(&str_type, haystack_len, args[3]); + } + + char *p = strstr(haystack + start, needle); + ssize_t pos = -1; + if (p) { + pos = p - haystack; + if (pos + needle_len > end) { + pos = -1; + } + } + return MP_OBJ_NEW_SMALL_INT(pos); +} + mp_obj_t str_strip(int n_args, const mp_obj_t *args) { assert(1 <= n_args && n_args <= 2); assert(MP_OBJ_IS_TYPE(args[0], &str_type)); @@ -248,11 +285,13 @@ mp_obj_t str_format(int n_args, const mp_obj_t *args) { return mp_obj_new_str(qstr_from_str_take(vstr->buf, vstr->alloc)); } +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); static MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); static MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, str_format); static const mp_method_t str_type_methods[] = { + { "find", &str_find_obj }, { "join", &str_join_obj }, { "strip", &str_strip_obj }, { "format", &str_format_obj }, diff --git a/py/objtype.c b/py/objtype.c index 6c89c1ff2b..011ee43552 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -27,15 +27,13 @@ static mp_obj_t mp_obj_new_class(mp_obj_t class) { return o; } -static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lookup_kind_t lookup_kind) { +static mp_map_elem_t *mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr, mp_map_lookup_kind_t lookup_kind) { for (;;) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type)); - mp_obj_type_t *self = self_in; - if (self->locals_dict == NULL) { + if (type->locals_dict == NULL) { return NULL; } - assert(MP_OBJ_IS_TYPE(self->locals_dict, &dict_type)); // Micro Python restriction, for now - mp_map_t *locals_map = ((void*)self->locals_dict + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object + assert(MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)); // Micro Python restriction, for now + mp_map_t *locals_map = ((void*)type->locals_dict + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), lookup_kind); if (elem != NULL) { return elem; @@ -44,25 +42,27 @@ static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lo // attribute not found, keep searching base classes // for a const struct, this entry might be NULL - if (self->bases_tuple == MP_OBJ_NULL) { + if (type->bases_tuple == MP_OBJ_NULL) { return NULL; } uint len; mp_obj_t *items; - mp_obj_tuple_get(self->bases_tuple, &len, &items); + mp_obj_tuple_get(type->bases_tuple, &len, &items); if (len == 0) { return NULL; } for (uint i = 0; i < len - 1; i++) { - elem = mp_obj_class_lookup(items[i], attr, lookup_kind); + assert(MP_OBJ_IS_TYPE(items[i], &mp_const_type)); + elem = mp_obj_class_lookup((mp_obj_type_t*)items[i], attr, lookup_kind); if (elem != NULL) { return elem; } } // search last base (simple tail recursion elimination) - self_in = items[len - 1]; + assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_const_type)); + type = (mp_obj_type_t*)items[len - 1]; } } @@ -73,11 +73,12 @@ static void class_print(void (*print)(void *env, const char *fmt, ...), void *en // args are reverse in the array static mp_obj_t class_make_new(mp_obj_t self_in, int n_args, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type)); + mp_obj_type_t *self = self_in; mp_obj_t o = mp_obj_new_class(self_in); // look for __init__ function - mp_map_elem_t *init_fn = mp_obj_class_lookup(self_in, MP_QSTR___init__, MP_MAP_LOOKUP); + mp_map_elem_t *init_fn = mp_obj_class_lookup(self, MP_QSTR___init__, MP_MAP_LOOKUP); if (init_fn != NULL) { // call __init__ function @@ -114,7 +115,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[1] = elem->value; return; } - elem = mp_obj_class_lookup((mp_obj_t)self->base.type, attr, MP_MAP_LOOKUP); + elem = mp_obj_class_lookup(self->base.type, attr, MP_MAP_LOOKUP); if (elem != NULL) { if (mp_obj_is_callable(elem->value)) { // class member is callable so build a bound method @@ -132,7 +133,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { static bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { // logic: look in class locals (no add) then obj members (add) (TODO check this against CPython) mp_obj_class_t *self = self_in; - mp_map_elem_t *elem = mp_obj_class_lookup((mp_obj_t)self->base.type, attr, MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_obj_class_lookup(self->base.type, attr, MP_MAP_LOOKUP); if (elem != NULL) { elem->value = value; } else { @@ -188,17 +189,47 @@ static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) // for fail, do nothing; for attr, dest[1] = value; for method, dest[0] = self, dest[1] = method static void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - mp_map_elem_t *elem = mp_obj_class_lookup(self_in, attr, MP_MAP_LOOKUP); + assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type)); + mp_obj_type_t *self = self_in; + mp_map_elem_t *elem = mp_obj_class_lookup(self, attr, MP_MAP_LOOKUP); if (elem != NULL) { dest[1] = elem->value; return; } + + // generic method lookup + // this is a lookup in the class itself (ie not the classes type or instance) + const mp_method_t *meth = self->methods; + if (meth != NULL) { + for (; meth->name != NULL; meth++) { + if (strcmp(meth->name, qstr_str(attr)) == 0) { + // 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(meth->fun, &mp_type_staticmethod)) { + // return just the function + dest[1] = ((mp_obj_staticmethod_t*)meth->fun)->fun; + } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) { + // return a bound method, with self being this class + dest[1] = ((mp_obj_classmethod_t*)meth->fun)->fun; + dest[0] = 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[1] = (mp_obj_t)meth->fun; + } + return; + } + } + } } static bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type)); + mp_obj_type_t *self = self_in; + // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation? - mp_map_elem_t *elem = mp_obj_class_lookup(self_in, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + mp_map_elem_t *elem = mp_obj_class_lookup(self, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); if (elem != NULL) { elem->value = value; return true; @@ -284,3 +315,16 @@ static mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) { } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance); + +/******************************************************************************/ +// staticmethod and classmethod types (probably should go in a different file) + +const mp_obj_type_t mp_type_staticmethod = { + { &mp_const_type }, + "staticmethod", +}; + +const mp_obj_type_t mp_type_classmethod = { + { &mp_const_type }, + "classmethod", +}; diff --git a/py/parse.c b/py/parse.c index d3786ba956..e2c9520736 100644 --- a/py/parse.c +++ b/py/parse.c @@ -88,6 +88,7 @@ typedef struct _parser_t { uint rule_stack_top; rule_stack_t *rule_stack; + uint result_stack_alloc; uint result_stack_top; mp_parse_node_t *result_stack; } parser_t; @@ -121,7 +122,7 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) { int num_parse_nodes_allocated = 0; mp_parse_node_struct_t *parse_node_new_struct(int rule_id, int num_args) { - mp_parse_node_struct_t *pn = m_malloc(sizeof(mp_parse_node_struct_t) + num_args * sizeof(mp_parse_node_t)); + mp_parse_node_struct_t *pn = m_new_obj_var(mp_parse_node_struct_t, mp_parse_node_t, num_args); pn->source = 0; // TODO pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8); num_parse_nodes_allocated += 1; @@ -180,6 +181,10 @@ static mp_parse_node_t peek_result(parser_t *parser, int pos) { } static void push_result_node(parser_t *parser, mp_parse_node_t pn) { + if (parser->result_stack_top >= parser->result_stack_alloc) { + parser->result_stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2); + parser->result_stack_alloc *= 2; + } parser->result_stack[parser->result_stack_top++] = pn; } @@ -191,7 +196,7 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) { } else if (tok->kind == MP_TOKEN_NUMBER) { bool dec = false; bool small_int = true; - int int_val = 0; + machine_int_t int_val = 0; int len = tok->len; const char *str = tok->str; int base = 10; @@ -211,7 +216,9 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) { i = 2; } } + bool overflow = false; for (; i < len; i++) { + machine_int_t old_val = int_val; if (unichar_isdigit(str[i]) && str[i] - '0' < base) { int_val = base * int_val + str[i] - '0'; } else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') { @@ -225,10 +232,17 @@ 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 + overflow = true; + } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) { + // If signed number changed sign - it's overflow + overflow = true; + } } if (dec) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn_copy(str, len)); - } else if (small_int && MP_FIT_SMALL_INT(int_val)) { + } else if (small_int && !overflow && MP_FIT_SMALL_INT(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_copy(str, len)); @@ -252,14 +266,20 @@ static void push_result_rule(parser_t *parser, const rule_t *rule, int num_args) } mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { - parser_t *parser = m_new(parser_t, 1); + + // allocate memory for the parser and its stacks + + parser_t *parser = m_new_obj(parser_t); + parser->rule_stack_alloc = 64; parser->rule_stack_top = 0; parser->rule_stack = m_new(rule_stack_t, parser->rule_stack_alloc); - parser->result_stack = m_new(mp_parse_node_t, 1000); + parser->result_stack_alloc = 64; parser->result_stack_top = 0; + parser->result_stack = m_new(mp_parse_node_t, parser->result_stack_alloc); + // work out the top-level rule to use, and push it on the stack int top_level_rule; switch (input_kind) { case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break; @@ -268,6 +288,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } push_rule(parser, rules[top_level_rule], 0); + // parse! + uint n, i; bool backtrack = false; const rule_t *rule; @@ -558,12 +580,25 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { //printf("--------------\n"); //result_stack_show(parser); - assert(parser->result_stack_top == 1); - //printf("maximum depth: %d\n", parser->rule_stack_alloc); + //printf("rule stack alloc: %d\n", parser->rule_stack_alloc); + //printf("result stack alloc: %d\n", parser->result_stack_alloc); //printf("number of parse nodes allocated: %d\n", num_parse_nodes_allocated); - return parser->result_stack[0]; + + // get the root parse node that we created + assert(parser->result_stack_top == 1); + mp_parse_node_t result = parser->result_stack[0]; + +finished: + // free the memory that we don't need anymore + m_del(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc); + m_del(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc); + m_del_obj(parser_t, parser); + + // return the result + return result; syntax_error: + // TODO these should raise a proper exception if (mp_lexer_is_kind(lex, MP_TOKEN_INDENT)) { mp_lexer_show_error_pythonic(lex, "IndentationError: unexpected indent"); } else if (mp_lexer_is_kind(lex, MP_TOKEN_DEDENT_MISMATCH)) { @@ -575,5 +610,6 @@ syntax_error: #endif mp_token_show(mp_lexer_cur(lex)); } - return MP_PARSE_NODE_NULL; + result = MP_PARSE_NODE_NULL; + goto finished; } diff --git a/py/runtime.c b/py/runtime.c index 63cb83da56..50ee37ec0d 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -90,6 +90,7 @@ void rt_init(void) { mp_map_add_qstr(&map_builtins, MP_QSTR_SyntaxError, mp_obj_new_exception(MP_QSTR_SyntaxError)); mp_map_add_qstr(&map_builtins, MP_QSTR_ValueError, mp_obj_new_exception(MP_QSTR_ValueError)); mp_map_add_qstr(&map_builtins, MP_QSTR_OSError, mp_obj_new_exception(MP_QSTR_OSError)); + mp_map_add_qstr(&map_builtins, MP_QSTR_AssertionError, mp_obj_new_exception(MP_QSTR_AssertionError)); // built-in objects mp_map_add_qstr(&map_builtins, MP_QSTR_Ellipsis, mp_const_ellipsis); @@ -267,10 +268,6 @@ void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_ar #endif } -static bool fit_small_int(mp_small_int_t o) { - return true; -} - int rt_is_true(mp_obj_t arg) { DEBUG_OP_printf("is true %p\n", arg); if (MP_OBJ_IS_SMALL_INT(arg)) { @@ -435,13 +432,10 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) { case RT_UNARY_OP_INVERT: val = ~val; break; default: assert(0); val = 0; } - if (fit_small_int(val)) { + if (MP_OBJ_FITS_SMALL_INT(val)) { return MP_OBJ_NEW_SMALL_INT(val); - } else { - // TODO make a bignum - assert(0); - return mp_const_none; } + return mp_obj_new_int(val); } else { // will be an object (small ints are caught in previous if) mp_obj_base_t *o = arg; if (o->type->unary_op != NULL) { @@ -550,9 +544,11 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { default: assert(0); } - if (fit_small_int(lhs_val)) { + // TODO: We just should make mp_obj_new_int() inline and use that + if (MP_OBJ_FITS_SMALL_INT(lhs_val)) { return MP_OBJ_NEW_SMALL_INT(lhs_val); } + return mp_obj_new_int(lhs_val); } else if (MP_OBJ_IS_TYPE(rhs, &float_type)) { return mp_obj_float_binary_op(op, lhs_val, rhs); } else if (MP_OBJ_IS_TYPE(rhs, &complex_type)) { @@ -809,12 +805,25 @@ void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { dest[0] = base; } else { // generic method lookup + // this is a lookup in the object (ie not class or type) const mp_method_t *meth = type->methods; if (meth != NULL) { for (; meth->name != NULL; meth++) { if (strcmp(meth->name, qstr_str(attr)) == 0) { - dest[1] = (mp_obj_t)meth->fun; - dest[0] = base; + // 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(meth->fun, &mp_type_staticmethod)) { + // return just the function + dest[1] = ((mp_obj_staticmethod_t*)meth->fun)->fun; + } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) { + // return a bound method, with self being the type of this object + dest[1] = ((mp_obj_classmethod_t*)meth->fun)->fun; + dest[0] = mp_obj_get_type(base); + } else { + // return a bound method, with self being this object + dest[1] = (mp_obj_t)meth->fun; + dest[0] = base; + } break; } } diff --git a/stm/Makefile b/stm/Makefile index 2fecd03bad..2facff81ce 100644 --- a/stm/Makefile +++ b/stm/Makefile @@ -105,6 +105,14 @@ SRC_STM = \ # usb_hcd.c \ # usb_hcd_int.c \ # usb_otg.c \ +# 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_CC3K = \ cc3000_common.c \ diff --git a/stm/lib/usb_bsp.c b/stm/lib/usb_bsp.c index c4839bdf96..e88e31db0e 100644 --- a/stm/lib/usb_bsp.c +++ b/stm/lib/usb_bsp.c @@ -117,6 +117,17 @@ void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) { GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
+ /*
+ // Configure ID pin (only in host mode)
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_OTG_FS);
+ */
+
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE);
}
@@ -138,6 +149,84 @@ void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev) { }
/**
+* @brief BSP_Drive_VBUS
+* Drives the Vbus signal through IO
+* @param state : VBUS states
+* @retval None
+*/
+
+void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state) {
+ //printf("DriveVBUS %p %u\n", pdev, state);
+ /*
+ On-chip 5 V VBUS generation is not supported. For this reason, a charge pump
+ or, if 5 V are available on the application board, a basic power switch, must
+ be added externally to drive the 5 V VBUS line. The external charge pump can
+ be driven by any GPIO output. When the application decides to power on VBUS
+ using the chosen GPIO, it must also set the port power bit in the host port
+ control and status register (PPWR bit in OTG_FS_HPRT).
+
+ Bit 12 PPWR: Port power
+ The application uses this field to control power to this port, and the core
+ clears this bit on an overcurrent condition.
+ */
+#if 0 // not implemented
+#ifndef USE_USB_OTG_HS
+ if (0 == state) {
+ /* DISABLE is needed on output of the Power Switch */
+ GPIO_SetBits(HOST_POWERSW_PORT, HOST_POWERSW_VBUS);
+ } else {
+ /*ENABLE the Power Switch by driving the Enable LOW */
+ GPIO_ResetBits(HOST_POWERSW_PORT, HOST_POWERSW_VBUS);
+ }
+#endif
+#endif
+}
+
+/**
+ * @brief USB_OTG_BSP_ConfigVBUS
+ * Configures the IO for the Vbus and OverCurrent
+ * @param None
+ * @retval None
+ */
+
+void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev) {
+ //printf("ConfigVBUS %p\n", pdev);
+#if 0 // not implemented
+#ifdef USE_USB_OTG_FS
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+#ifdef USE_STM3210C_EVAL
+ RCC_APB2PeriphClockCmd(HOST_POWERSW_PORT_RCC, ENABLE);
+
+
+ /* Configure Power Switch Vbus Pin */
+ GPIO_InitStructure.GPIO_Pin = HOST_POWERSW_VBUS;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_Init(HOST_POWERSW_PORT, &GPIO_InitStructure);
+#else
+ #ifdef USE_USB_OTG_FS
+ RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOH , ENABLE);
+
+ GPIO_InitStructure.GPIO_Pin = HOST_POWERSW_VBUS;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
+ GPIO_Init(HOST_POWERSW_PORT,&GPIO_InitStructure);
+ #endif
+#endif
+
+ /* By Default, DISABLE is needed on output of the Power Switch */
+ GPIO_SetBits(HOST_POWERSW_PORT, HOST_POWERSW_VBUS);
+
+ USB_OTG_BSP_mDelay(200); /* Delay is need for stabilising the Vbus Low
+ in Reset Condition, when Vbus=1 and Reset-button is pressed by user */
+#endif
+#endif
+}
+
+/**
* @brief USB_OTG_BSP_uDelay
* This function provides delay time in micro sec
* @param usec : Value of delay required in micro sec
diff --git a/stm/lib/usb_conf.h b/stm/lib/usb_conf.h index 5e736f91e2..a51a23a84e 100644 --- a/stm/lib/usb_conf.h +++ b/stm/lib/usb_conf.h @@ -181,10 +181,65 @@ /****************** USB OTG MISC CONFIGURATION ********************************/
#define VBUS_SENSING_ENABLED
+/* BEGIN host specific stuff */
+
+/*******************************************************************************
+* FIFO Size Configuration in Host mode
+*
+* (i) Receive data FIFO size = (Largest Packet Size / 4) + 1 or
+* 2x (Largest Packet Size / 4) + 1, If a
+* high-bandwidth channel or multiple isochronous
+* channels are enabled
+*
+* (ii) For the host nonperiodic Transmit FIFO is the largest maximum packet size
+* for all supported nonperiodic OUT channels. Typically, a space
+* corresponding to two Largest Packet Size is recommended.
+*
+* (iii) The minimum amount of RAM required for Host periodic Transmit FIFO is
+* the largest maximum packet size for all supported periodic OUT channels.
+* If there is at least one High Bandwidth Isochronous OUT endpoint,
+* then the space must be at least two times the maximum packet size for
+* that channel.
+*******************************************************************************/
+
+/****************** USB OTG HS CONFIGURATION (for host) ***********************/
+#ifdef USB_OTG_HS_CORE
+ #define RX_FIFO_HS_SIZE 512
+ #define TXH_NP_HS_FIFOSIZ 256
+ #define TXH_P_HS_FIFOSIZ 256
+
+// #define USB_OTG_HS_LOW_PWR_MGMT_SUPPORT
+// #define USB_OTG_HS_SOF_OUTPUT_ENABLED
+
+// #define USB_OTG_INTERNAL_VBUS_ENABLED
+#define USB_OTG_EXTERNAL_VBUS_ENABLED
+
+ #ifdef USE_ULPI_PHY
+ #define USB_OTG_ULPI_PHY_ENABLED
+ #endif
+ #ifdef USE_EMBEDDED_PHY
+ #define USB_OTG_EMBEDDED_PHY_ENABLED
+ #endif
+ #define USB_OTG_HS_INTERNAL_DMA_ENABLED
+// #define USB_OTG_HS_DEDICATED_EP1_ENABLED
+#endif
+
+/****************** USB OTG FS CONFIGURATION (for host) ***********************/
+#ifdef USB_OTG_FS_CORE
+ //#define RX_FIFO_FS_SIZE 128 // already defined for device (and it's the same)
+ #define TXH_NP_FS_FIFOSIZ 96
+ #define TXH_P_FS_FIFOSIZ 96
+
+// #define USB_OTG_FS_LOW_PWR_MGMT_SUPPORT
+// #define USB_OTG_FS_SOF_OUTPUT_ENABLED
+#endif
+
+/* END host specific stuff */
+
/****************** USB OTG MODE CONFIGURATION ********************************/
-//#define USE_HOST_MODE
+//#define USE_HOST_MODE // set in Makefile
#define USE_DEVICE_MODE
-//#define USE_OTG_MODE
+//#define USE_OTG_MODE // set in Makefile
#ifndef USB_OTG_FS_CORE
#ifndef USB_OTG_HS_CORE
diff --git a/stm/lib/usb_core.c b/stm/lib/usb_core.c index 4b28c085f2..b0cce88046 100644 --- a/stm/lib/usb_core.c +++ b/stm/lib/usb_core.c @@ -617,7 +617,7 @@ USB_OTG_STS USB_OTG_CoreInitHost(USB_OTG_CORE_HANDLE *pdev) USB_OTG_HCFG_TypeDef hcfg;
#ifdef USE_OTG_MODE
- USB_OTG_OTGCTL_TypeDef gotgctl;
+ USB_OTG_GOTGCTL_TypeDef gotgctl;
#endif
uint32_t i = 0;
diff --git a/stm/main.c b/stm/main.c index 44db47f13b..cdc4432c09 100644 --- a/stm/main.c +++ b/stm/main.c @@ -307,7 +307,9 @@ char *strdup(const char *str) { static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; void stdout_tx_str(const char *str) { - //usart_tx_str(str); // disabled because usart is a Python object and we now need specify which USART port + if (pyb_usart_global_debug != PYB_USART_NONE) { + usart_tx_str(pyb_usart_global_debug, str); + } usb_vcp_send_str(str); } @@ -322,10 +324,10 @@ int readline(vstr_t *line, const char *prompt) { if (usb_vcp_rx_any() != 0) { c = usb_vcp_rx_get(); break; - } /*else if (usart_rx_any()) { // disabled because usart is a Python object and we now need specify which USART port - c = usart_rx_char(); + } else if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) { + c = usart_rx_char(pyb_usart_global_debug); break; - }*/ + } sys_tick_delay_ms(1); if (storage_needs_flush()) { storage_flush(); @@ -775,7 +777,9 @@ int main(void) { switch_init(); storage_init(); - //usart_init(); disabled while wi-fi is enabled; also disabled because now usart is a proper Python object + // uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP + //pyb_usart_global_debug = PYB_USART_6; + //usart_init(pyb_usart_global_debug, 115200); int first_soft_reset = true; @@ -937,6 +941,9 @@ soft_reset: // USB usb_init(); + // USB host; not working! + //pyb_usbh_init(); + // MMA if (first_soft_reset) { // init and reset address to zero diff --git a/stm/printf.c b/stm/printf.c index 8a40a61a5f..c0fa82e1b0 100644 --- a/stm/printf.c +++ b/stm/printf.c @@ -206,6 +206,21 @@ int pfenv_printf(const pfenv_t *pfenv, const char *fmt, va_list args) { case 'P': // ? chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, width); break; + case 'g': + { + // This is a very hacky approach to printing floats. Micropython + // uses %g when using print, and I just wanted to see somthing + // usable. I expect that this will be replaced with something + // more appropriate. + char dot = '.'; + double d = va_arg(args, double); + int left = (int)d; + int right = (int)((d - (double)(int)d) * 1000000.0); + chrs += pfenv_print_int(pfenv, left, 1, 10, 'a', flags, width); + chrs += pfenv_print_strn(pfenv, &dot, 1, flags, width); + chrs += pfenv_print_int(pfenv, right, 0, 10, 'a', PF_FLAG_ZERO_PAD, 6); + break; + } default: pfenv->print_strn(pfenv->data, fmt, 1); chrs += 1; @@ -220,12 +235,10 @@ void stdout_print_strn(void *data, const char *str, unsigned int len) { // send stdout to USART, USB CDC VCP, and LCD if nothing else bool any = false; - // TODO should have a setting for which USART port to send to - if (usart_is_enabled()) { - usart_tx_strn_cooked(str, len); + if (pyb_usart_global_debug != PYB_USART_NONE) { + usart_tx_strn_cooked(pyb_usart_global_debug, str, len); any = true; } - if (usb_vcp_is_enabled()) { usb_vcp_send_strn_cooked(str, len); any = true; diff --git a/stm/stm32fxxx_it.c b/stm/stm32fxxx_it.c index e254ccc899..c1a9a0702f 100644 --- a/stm/stm32fxxx_it.c +++ b/stm/stm32fxxx_it.c @@ -31,6 +31,7 @@ #include "stm32fxxx_it.h" #include "stm32f4xx_exti.h" #include "usb_core.h" +//#include "usb_hcd_int.h" // for usb host mode only //#include "usbd_core.h" //#include "usbd_cdc_core.h" @@ -197,7 +198,8 @@ void OTG_HS_IRQHandler(void) void OTG_FS_IRQHandler(void) #endif { - USBD_OTG_ISR_Handler (&USB_OTG_dev); + USBD_OTG_ISR_Handler (&USB_OTG_dev); // device mode + //USBH_OTG_ISR_Handler (&USB_OTG_dev); // host mode FIXME } #ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED diff --git a/stm/usart.c b/stm/usart.c index bc5bfc7369..5f47ec788a 100644 --- a/stm/usart.c +++ b/stm/usart.c @@ -8,20 +8,14 @@ #include "obj.h" #include "usart.h" -static bool is_enabled; - -typedef enum { - PYB_USART_1 = 1, - PYB_USART_2 = 2, - PYB_USART_3 = 3, - PYB_USART_6 = 4, - PYB_USART_MAX = 4, -} pyb_usart_t; +pyb_usart_t pyb_usart_global_debug = PYB_USART_NONE; static USART_TypeDef *usart_get_base(pyb_usart_t usart_id) { USART_TypeDef *USARTx=NULL; switch (usart_id) { + case PYB_USART_NONE: + break; case PYB_USART_1: USARTx = USART1; break; @@ -52,6 +46,9 @@ void usart_init(pyb_usart_t usart_id, uint32_t baudrate) { void (*RCC_APBxPeriphClockCmd)(uint32_t, FunctionalState)=NULL; switch (usart_id) { + case PYB_USART_NONE: + return; + case PYB_USART_1: USARTx = USART1; @@ -128,16 +125,13 @@ void usart_init(pyb_usart_t usart_id, uint32_t baudrate) { USART_Cmd(USARTx, ENABLE); } -bool usart_is_enabled(void) { - return is_enabled; -} - -bool usart_rx_any(void) { - return USART_GetFlagStatus(USART6, USART_FLAG_RXNE) == SET; +bool usart_rx_any(pyb_usart_t usart_id) { + USART_TypeDef *USARTx = usart_get_base(usart_id); + return USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == SET; } int usart_rx_char(pyb_usart_t usart_id) { - USART_TypeDef *USARTx= usart_get_base(usart_id); + USART_TypeDef *USARTx = usart_get_base(usart_id); return USART_ReceiveData(USARTx); } @@ -176,8 +170,8 @@ typedef struct _pyb_usart_obj_t { } pyb_usart_obj_t; static mp_obj_t usart_obj_status(mp_obj_t self_in) { - // TODO make it check the correct USART port! - if (usart_rx_any()) { + pyb_usart_obj_t *self = self_in; + if (usart_rx_any(self->usart_id)) { return mp_const_true; } else { return mp_const_false; diff --git a/stm/usart.h b/stm/usart.h index 15ed419fe7..541cb757c8 100644 --- a/stm/usart.h +++ b/stm/usart.h @@ -1 +1,18 @@ +typedef enum { + PYB_USART_NONE = 0, + PYB_USART_1 = 1, + PYB_USART_2 = 2, + PYB_USART_3 = 3, + PYB_USART_6 = 4, + PYB_USART_MAX = 4, +} pyb_usart_t; + +extern pyb_usart_t pyb_usart_global_debug; + +void usart_init(pyb_usart_t usart_id, uint32_t baudrate); +bool usart_rx_any(pyb_usart_t usart_id); +int usart_rx_char(pyb_usart_t usart_id); +void usart_tx_str(pyb_usart_t usart_id, const char *str); +void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len); + mp_obj_t pyb_Usart(mp_obj_t usart_id, mp_obj_t baudrate); @@ -80,7 +80,7 @@ void usb_vcp_send_strn(const char *str, int len) { } } -#include "lib/usbd_conf.h" +#include "usbd_conf.h" /* These are external variables imported from CDC core to be used for IN transfer management. */ @@ -105,3 +105,30 @@ void usb_vcp_send_strn_cooked(const char *str, int len) { void usb_hid_send_report(uint8_t *buf) { USBD_HID_SendReport(&USB_OTG_dev, buf, 4); } + +/******************************************************************************/ +// code for experimental USB OTG support + +#ifdef USE_HOST_MODE + +#include "lib-otg/usbh_core.h" +#include "lib-otg/usbh_usr.h" +#include "lib-otg/usbh_hid_core.h" + +__ALIGN_BEGIN USBH_HOST USB_Host __ALIGN_END ; + +static int host_is_enabled = 0; +void pyb_usbh_init(void) { + if (!host_is_enabled) { + // only init USBH once in the device's power-lifetime + /* Init Host Library */ + USBH_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USB_Host, &HID_cb, &USR_Callbacks); + } + host_is_enabled = 1; +} + +void pyb_usbh_process(void) { + USBH_Process(&USB_OTG_dev, &USB_Host); +} + +#endif // USE_HOST_MODE @@ -6,3 +6,6 @@ void usb_vcp_send_str(const char* str); void usb_vcp_send_strn(const char* str, int len); void usb_vcp_send_strn_cooked(const char *str, int len); void usb_hid_send_report(uint8_t *buf); // 4 bytes for mouse: ?, x, y, ? + +void pyb_usbh_init(void); +void pyb_usbh_process(void); diff --git a/teensy/Makefile b/teensy/Makefile index ade9b37040..8046f862ac 100644 --- a/teensy/Makefile +++ b/teensy/Makefile @@ -33,7 +33,8 @@ SRC_C = \ lcd.c \ led.c \ lexerfatfs.c \ - usart.c \ + lexermemzip.c \ + memzip.c \ usb.c \ STM_SRC_C = \ @@ -60,9 +61,9 @@ OBJ = $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(STM_SRC_S:.s=.o #LIB += -ltermcap all2: $(BUILD) hex -hex: $(BUILD)/flash.hex +hex: $(BUILD)/micropython-mz.hex -post_compile: $(BUILD)/flash.hex +post_compile: $(BUILD)/micropython-mz.hex $(ECHO) "Preparing $@ for upload" $(Q)$(TOOLS_PATH)/teensy_post_compile -file="$(basename $(<F))" -path="$(<D)" -tools="$(TOOLS_PATH)" @@ -72,11 +73,19 @@ reboot: upload: post_compile reboot -$(BUILD)/flash.elf: $(OBJ) +$(BUILD)/micropython.elf: $(OBJ) $(ECHO) "LINK $<" $(Q)$(CC) $(LDFLAGS) -o "$@" -Wl,-Map,$(@:.elf=.map) $(OBJ) $(LIBS) $(Q)$(SIZE) $@ +ifeq ($(MEMZIP_DIR),) +MEMZIP_DIR = memzip_files +endif + +$(BUILD)/micropython-mz.hex: $(BUILD)/micropython.hex $(shell find ${MEMZIP_DIR} -type f) + @$(ECHO) "Creating $@" + $(Q)./add-memzip.sh $< $@ ${MEMZIP_DIR} + $(BUILD)/%.hex: $(BUILD)/%.elf $(ECHO) "HEX $<" $(Q)$(OBJCOPY) -O ihex -R .eeprom "$<" "$@" diff --git a/teensy/add-memzip.sh b/teensy/add-memzip.sh new file mode 100755 index 0000000000..a00489effd --- /dev/null +++ b/teensy/add-memzip.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +if [ "$#" != 3 ]; then + echo "Usage: add-memzip.sh input.hex output.hex file-directory" + exit 1 +fi + +#set -x + +input_hex=$1 +output_hex=$2 +memzip_src_dir=$3 + +input_bin=${input_hex}.bin +output_bin=${output_hex}.bin +zip_file=${output_hex}.zip +zip_base=$(basename ${zip_file}) +zip_dir=$(dirname ${zip_file}) +abs_zip_dir=$(realpath ${zip_dir}) + +rm -f ${zip_file} +(cd ${memzip_src_dir}; zip -0 -r -D ${abs_zip_dir}/${zip_base} .) +objcopy -I ihex -O binary ${input_hex} ${input_bin} +cat ${input_bin} ${zip_file} > ${output_bin} +objcopy -I binary -O ihex ${output_bin} ${output_hex} +echo "Added ${memzip_src_dir} to ${input_hex} creating ${output_hex}" + diff --git a/teensy/lexermemzip.c b/teensy/lexermemzip.c new file mode 100644 index 0000000000..2f808ee429 --- /dev/null +++ b/teensy/lexermemzip.c @@ -0,0 +1,18 @@ +#include <stdint.h> +#include <stdlib.h> + +#include "misc.h" +#include "lexer.h" +#include "memzip.h" + +mp_lexer_t *mp_lexer_new_from_memzip_file(const char *filename) +{ + void *data; + size_t len; + + if (memzip_locate(filename, &data, &len) != MZ_OK) { + return NULL; + } + return mp_lexer_new_from_str_len(filename, (const char *)data, (uint)len, 0); +} + diff --git a/teensy/lexermemzip.h b/teensy/lexermemzip.h new file mode 100644 index 0000000000..e5d4be5eae --- /dev/null +++ b/teensy/lexermemzip.h @@ -0,0 +1,2 @@ +mp_lexer_t *mp_lexer_new_from_memzip_file(const char *filename); + diff --git a/teensy/main.c b/teensy/main.c index fd5aec0459..d5860cd9d4 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -8,6 +8,7 @@ #include "mpconfig.h" #include "mpqstr.h" #include "lexer.h" +#include "lexermemzip.h" #include "parse.h" #include "obj.h" #include "compile.h" @@ -22,52 +23,17 @@ extern uint32_t _heap_start; -#ifdef USE_READLINE -#include <readline/readline.h> -#include <readline/history.h> -#endif +bool do_file(const char *filename); -#if 0 -static char *str_join(const char *s1, int sep_char, const char *s2) { - int l1 = strlen(s1); - int l2 = strlen(s2); - char *s = m_new(char, l1 + l2 + 2); - memcpy(s, s1, l1); - if (sep_char != 0) { - s[l1] = sep_char; - l1 += 1; +void flash_error(int n) { + for (int i = 0; i < n; i++) { + led_state(PYB_LED_BUILTIN, 1); + delay(250); + led_state(PYB_LED_BUILTIN, 0); + delay(250); } - memcpy(s + l1, s2, l2); - s[l1 + l2] = 0; - return s; } -static char *prompt(char *p) { -#ifdef USE_READLINE - char *line = readline(p); - if (line) { - add_history(line); - } -#else - static char buf[256]; - fputs(p, stdout); - char *s = fgets(buf, sizeof(buf), stdin); - if (!s) { - return NULL; - } - int l = strlen(buf); - if (buf[l - 1] == '\n') { - buf[l - 1] = 0; - } else { - l++; - } - char *line = m_new(char, l); - memcpy(line, buf, l); -#endif - return line; -} -#endif - static const char *help_text = "Welcome to Micro Python!\n\n" "This is a *very* early version of Micro Python and has minimal functionality.\n\n" @@ -215,6 +181,19 @@ mp_obj_t pyb_hid_send_report(mp_obj_t arg) { } #endif +static qstr pyb_config_source_dir = 0; +static qstr pyb_config_main = 0; + +mp_obj_t pyb_source_dir(mp_obj_t source_dir) { + pyb_config_source_dir = mp_obj_get_qstr(source_dir); + return mp_const_none; +} + +mp_obj_t pyb_main(mp_obj_t main) { + pyb_config_main = mp_obj_get_qstr(main); + return mp_const_none; +} + mp_obj_t pyb_delay(mp_obj_t count) { delay(mp_obj_get_int(count)); return mp_const_none; @@ -225,6 +204,12 @@ mp_obj_t pyb_led(mp_obj_t state) { return state; } +mp_obj_t pyb_run(mp_obj_t filename_obj) { + const char *filename = qstr_str(mp_obj_get_qstr(filename_obj)); + do_file(filename); + return mp_const_none; +} + char *strdup(const char *str) { uint32_t len = strlen(str); char *s2 = m_new(char, len + 1); @@ -316,6 +301,39 @@ int readline(vstr_t *line, const char *prompt) { } } +bool do_file(const char *filename) { + mp_lexer_t *lex = mp_lexer_new_from_memzip_file(filename); + + if (lex == NULL) { + printf("could not open file '%s' for reading\n", filename); + return false; + } + + mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_lexer_free(lex); + + if (pn == MP_PARSE_NODE_NULL) { + return false; + } + + mp_obj_t module_fun = mp_compile(pn, false); + if (module_fun == mp_const_none) { + return false; + } + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + rt_call_function_0(module_fun); + nlr_pop(); + return true; + } else { + // uncaught exception + mp_obj_print((mp_obj_t)nlr.ret_val); + printf("\n"); + return false; + } +} + void do_repl(void) { stdout_tx_str("Micro Python for Teensy 3.1\r\n"); stdout_tx_str("Type \"help()\" for more information.\r\n"); @@ -397,24 +415,53 @@ soft_reset: rt_init(); #if 1 - printf("About to add functions()\n"); // add some functions to the python namespace { rt_store_name(qstr_from_str_static("help"), rt_make_function_0(pyb_help)); mp_obj_t m = mp_obj_new_module(qstr_from_str_static("pyb")); rt_store_attr(m, qstr_from_str_static("info"), rt_make_function_0(pyb_info)); + rt_store_attr(m, qstr_from_str_static("source_dir"), rt_make_function_1(pyb_source_dir)); + rt_store_attr(m, qstr_from_str_static("main"), rt_make_function_1(pyb_main)); rt_store_attr(m, qstr_from_str_static("gc"), rt_make_function_0(pyb_gc)); rt_store_attr(m, qstr_from_str_static("delay"), rt_make_function_1(pyb_delay)); rt_store_attr(m, qstr_from_str_static("led"), rt_make_function_1(pyb_led)); rt_store_attr(m, qstr_from_str_static("Led"), rt_make_function_1(pyb_Led)); rt_store_attr(m, qstr_from_str_static("gpio"), (mp_obj_t)&pyb_gpio_obj); rt_store_name(qstr_from_str_static("pyb"), m); + rt_store_name(qstr_from_str_static("run"), rt_make_function_1(pyb_run)); } #endif + if (!do_file("/boot.py")) { + printf("Unable to open '/boot.py'\n"); + flash_error(4); + } + // Turn bootup LED off led_state(PYB_LED_BUILTIN, 0); + // run main script + { + vstr_t *vstr = vstr_new(); + vstr_add_str(vstr, "/"); + if (pyb_config_source_dir == 0) { + vstr_add_str(vstr, "src"); + } else { + vstr_add_str(vstr, qstr_str(pyb_config_source_dir)); + } + vstr_add_char(vstr, '/'); + if (pyb_config_main == 0) { + vstr_add_str(vstr, "main.py"); + } else { + vstr_add_str(vstr, qstr_str(pyb_config_main)); + } + if (!do_file(vstr_str(vstr))) { + printf("Unable to open '%s'\n", vstr_str(vstr)); + flash_error(3); + } + vstr_free(vstr); + } + do_repl(); printf("PYB: soft reboot\n"); diff --git a/teensy/memzip.c b/teensy/memzip.c new file mode 100644 index 0000000000..ec6c26980c --- /dev/null +++ b/teensy/memzip.c @@ -0,0 +1,37 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "memzip.h" + +extern uint8_t _staticfs[]; + +MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) +{ + const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)_staticfs; + uint8_t *mem_data; + + /* Zip file filenames don't have a leading /, so we strip it off */ + + if (*filename == '/') { + filename++; + } + while (file_hdr->signature == MEMZIP_FILE_HEADER_SIGNATURE) { + const char *file_hdr_filename = (const char *)&file_hdr[1]; + mem_data = (uint8_t *)file_hdr_filename; + mem_data += file_hdr->filename_len; + mem_data += file_hdr->extra_len; + if (!strncmp(file_hdr_filename, filename, file_hdr->filename_len)) { + /* We found a match */ + if (file_hdr->compression_method != 0) { + return MZ_FILE_COMPRESSED; + } + + *data = mem_data; + *len = file_hdr->uncompressed_size; + return MZ_OK; + } + mem_data += file_hdr->uncompressed_size; + file_hdr = (const MEMZIP_FILE_HDR *)mem_data; + } + return MZ_NO_FILE; +} diff --git a/teensy/memzip.h b/teensy/memzip.h new file mode 100644 index 0000000000..ecbd98763c --- /dev/null +++ b/teensy/memzip.h @@ -0,0 +1,73 @@ +#pragma pack(push, 1) + +#define MEMZIP_FILE_HEADER_SIGNATURE 0x04034b50 +typedef struct +{ + uint32_t signature; + uint16_t version; + uint16_t flags; + uint16_t compression_method; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_len; + uint16_t extra_len; + + /* char filename[filename_len] */ + /* uint8_t extra[extra_len] */ + +} MEMZIP_FILE_HDR; + +#define MEMZIP_CENTRAL_DIRECTORY_SIGNATURE 0x02014b50 +typedef struct +{ + uint32_t signature; + uint16_t version_made_by; + uint16_t version_read_with; + uint16_t flags; + uint16_t compression_method; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_len; + uint16_t extra_len; + uint16_t disk_num; + uint16_t internal_file_attributes; + uint32_t external_file_attributes; + uint32_t file_header_offset; + + /* char filename[filename_len] */ + /* uint8_t extra[extra_len] */ + +} MEMZIP_CENTRAL_DIRECTORY_HDR; + +#define MEMZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE 0x06054b50 +typedef struct +{ + uint32_t signature; + uint16_t disk_num; + uint16_t central_directory_disk; + uint16_t num_central_directories_this_disk; + uint16_t total_central_directories; + uint32_t central_directory_size; + uint32_t central_directory_offset; + uint16_t comment_len; + + /* char comment[comment_len] */ + +} MEMZIP_END_OF_CENTRAL_DIRECTORY; + +#pragma pack(pop) + +typedef enum { + MZ_OK = 0, /* (0) Succeeded */ + MZ_NO_FILE, /* (1) Could not find the file. */ + MZ_FILE_COMPRESSED, /* (2) File is compressed (expecting uncompressed) */ + +} MEMZIP_RESULT; + +MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len); diff --git a/teensy/memzip_files/boot.py b/teensy/memzip_files/boot.py new file mode 100644 index 0000000000..3fe9f05e53 --- /dev/null +++ b/teensy/memzip_files/boot.py @@ -0,0 +1 @@ +print("Executing boot.py") diff --git a/teensy/memzip_files/src/main.py b/teensy/memzip_files/src/main.py new file mode 100644 index 0000000000..8fc08db15e --- /dev/null +++ b/teensy/memzip_files/src/main.py @@ -0,0 +1,11 @@ +print("Executing main.py") + +x=pyb.led(1) +pyb.delay(100) +x=pyb.led(0) +pyb.delay(100) +x=pyb.led(1) +pyb.delay(100) +x=pyb.led(0) + + diff --git a/teensy/memzip_files/src/test.py b/teensy/memzip_files/src/test.py new file mode 100644 index 0000000000..7957b27caf --- /dev/null +++ b/teensy/memzip_files/src/test.py @@ -0,0 +1 @@ +print("Executing /src/test.py") diff --git a/teensy/memzip_files/test.py b/teensy/memzip_files/test.py new file mode 100644 index 0000000000..088cb4383a --- /dev/null +++ b/teensy/memzip_files/test.py @@ -0,0 +1 @@ +print("Executing /test.py") diff --git a/teensy/mk20dx256.ld b/teensy/mk20dx256.ld index da57cbe5cb..e46efd3e26 100644 --- a/teensy/mk20dx256.ld +++ b/teensy/mk20dx256.ld @@ -126,6 +126,12 @@ SECTIONS _edata = .; } > RAM + /* + * _staticfs is the place in flash where the static filesystem which + * is concatenated to the .hex file will wind up. + */ + _staticfs = LOADADDR(.data) + SIZEOF(.data); + .noinit (NOLOAD) : { *(.noinit*) } > RAM diff --git a/tests/basics/tests/int-small.py b/tests/basics/tests/int-small.py new file mode 100644 index 0000000000..be338c4a4c --- /dev/null +++ b/tests/basics/tests/int-small.py @@ -0,0 +1,26 @@ +# This test small int range for 32-bit machine + +a = 0x3fffff +print(a) +a *= 0x10 +print(a) +a *= 0x10 +print(a) +a += 0xff +print(a) +# This would overflow +#a += 1 + +a = -0x3fffff +print(a) +a *= 0x10 +print(a) +a *= 0x10 +print(a) +a -= 0xff +print(a) +# This still doesn't overflow +a -= 1 +print(a) +# This would overflow +#a -= 1 diff --git a/tests/basics/tests/list1.py b/tests/basics/tests/list1.py index 8caa9e17c6..250a12b704 100644 --- a/tests/basics/tests/list1.py +++ b/tests/basics/tests/list1.py @@ -10,3 +10,9 @@ print(x) f = x.append f(4) print(x) + +x.extend([100, 200]) +print(x) + +x += [2, 1] +print(x) diff --git a/tests/basics/tests/list_compare.py b/tests/basics/tests/list_compare.py new file mode 100644 index 0000000000..eea8814247 --- /dev/null +++ b/tests/basics/tests/list_compare.py @@ -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] == [1, 0]) + +print([1] > [1]) +print([1] > [2]) +print([2] > [1]) +print([1, 0] > [1]) +print([1, -1] > [1]) +print([1] > [1, 0]) +print([1] > [1, -1]) + +print([1] < [1]) +print([2] < [1]) +print([1] < [2]) +print([1] < [1, 0]) +print([1] < [1, -1]) +print([1, 0] < [1]) +print([1, -1] < [1]) + +print([1] >= [1]) +print([1] >= [2]) +print([2] >= [1]) +print([1, 0] >= [1]) +print([1, -1] >= [1]) +print([1] >= [1, 0]) +print([1] >= [1, -1]) + +print([1] <= [1]) +print([2] <= [1]) +print([1] <= [2]) +print([1] <= [1, 0]) +print([1] <= [1, -1]) +print([1, 0] <= [1]) +print([1, -1] <= [1]) diff --git a/tests/basics/tests/set_add.py b/tests/basics/tests/set_add.py new file mode 100644 index 0000000000..f2a372f307 --- /dev/null +++ b/tests/basics/tests/set_add.py @@ -0,0 +1,5 @@ +s = {1, 2, 3, 4} +print(s.add(5)) +l = list(s) +l.sort() +print(l) diff --git a/tests/basics/tests/set_binop.py b/tests/basics/tests/set_binop.py new file mode 100644 index 0000000000..d0d0b8027b --- /dev/null +++ b/tests/basics/tests/set_binop.py @@ -0,0 +1,30 @@ +def r(s): + l = list(s) + l.sort() + return l +sets = [set(), {1}, {1, 2}, {1, 2, 3}, {2, 3}, {2, 3, 5}, {5}, {7}] +for s in sets: + for t in sets: + print(s, '|', t, '=', r(s | t)) + print(s, '^', t, '=', r(s ^ t)) + print(s, '&', t, '=', r(s & t)) + print(s, '-', t, '=', r(s - t)) + u = s.copy() + u |= t + print(s, "|=", t, '-->', r(u)) + u = s.copy() + u ^= t + print(s, "^=", t, '-->', r(u)) + u = s.copy() + u &= t + print(s, "&=", t, "-->", r(u)) + u = s.copy() + u -= t + print(s, "-=", t, "-->", r(u)) + + print(s, '==', t, '=', s == t) + print(s, '!=', t, '=', s != t) + print(s, '>', t, '=', s > t) + print(s, '>=', t, '=', s >= t) + print(s, '<', t, '=', s < t) + print(s, '<=', t, '=', s <= t) diff --git a/tests/basics/tests/set_clear.py b/tests/basics/tests/set_clear.py new file mode 100644 index 0000000000..6fda93f0fb --- /dev/null +++ b/tests/basics/tests/set_clear.py @@ -0,0 +1,3 @@ +s = {1, 2, 3, 4} +print(s.clear()) +print(list(s)) diff --git a/tests/basics/tests/set_copy.py b/tests/basics/tests/set_copy.py new file mode 100644 index 0000000000..2ea308b0db --- /dev/null +++ b/tests/basics/tests/set_copy.py @@ -0,0 +1,8 @@ +s = {1, 2, 3, 4} +t = s.copy() +s.add(5) +t.add(7) +for i in s, t: + l = list(i) + l.sort() + print(l) diff --git a/tests/basics/tests/set_difference.py b/tests/basics/tests/set_difference.py new file mode 100644 index 0000000000..26976116f3 --- /dev/null +++ b/tests/basics/tests/set_difference.py @@ -0,0 +1,21 @@ +def report(s): + l = list(s) + l.sort() + print(l) + +l = [1, 2, 3, 4] +s = set(l) +outs = [s.difference(), + s.difference({1}), + s.difference({1}, [1, 2]), + s.difference({1}, {1, 2}, {2, 3})] +for out in outs: + report(out) + +s = set(l) +print(s.difference_update()) +report(s) +print(s.difference_update({1})) +report(s) +print(s.difference_update({1}, [2])) +report(s) diff --git a/tests/basics/tests/set_discard.py b/tests/basics/tests/set_discard.py new file mode 100644 index 0000000000..baac26413c --- /dev/null +++ b/tests/basics/tests/set_discard.py @@ -0,0 +1,3 @@ +s = {1, 2} +print(s.discard(1)) +print(list(s)) diff --git a/tests/basics/tests/set_intersection.py b/tests/basics/tests/set_intersection.py new file mode 100644 index 0000000000..6f3dfc7414 --- /dev/null +++ b/tests/basics/tests/set_intersection.py @@ -0,0 +1,12 @@ +def report(s): + l = list(s) + l.sort() + print(l) + +s = {1, 2, 3, 4} +report(s) +report(s.intersection({1, 3})) +report(s.intersection([3, 4])) + +print(s.intersection_update([1])) +report(s) diff --git a/tests/basics/tests/set_isdisjoint.py b/tests/basics/tests/set_isdisjoint.py new file mode 100644 index 0000000000..7fb7e769bb --- /dev/null +++ b/tests/basics/tests/set_isdisjoint.py @@ -0,0 +1,6 @@ +s = {1, 2, 3, 4} +print(s.isdisjoint({1})) +print(s.isdisjoint([2])) +print(s.isdisjoint([])) +print(s.isdisjoint({7,8,9,10})) +print(s.isdisjoint([7,8,9,1])) diff --git a/tests/basics/tests/set_isfooset.py b/tests/basics/tests/set_isfooset.py new file mode 100644 index 0000000000..ce7952cd2c --- /dev/null +++ b/tests/basics/tests/set_isfooset.py @@ -0,0 +1,5 @@ +sets = [set(), {1}, {1, 2, 3}, {3, 4, 5}, {5, 6, 7}] +for i in sets: + for j in sets: + print(i.issubset(j)) + print(i.issuperset(j)) diff --git a/tests/basics/tests/set_iter.py b/tests/basics/tests/set_iter.py new file mode 100644 index 0000000000..2960177303 --- /dev/null +++ b/tests/basics/tests/set_iter.py @@ -0,0 +1,5 @@ +s = {1, 2, 3, 4} +l = list(s) +l.sort() +print(l) + diff --git a/tests/basics/tests/set_pop.py b/tests/basics/tests/set_pop.py new file mode 100644 index 0000000000..0cd478ce25 --- /dev/null +++ b/tests/basics/tests/set_pop.py @@ -0,0 +1,9 @@ +s = {1} +print(s.pop()) +try: + print(s.pop(), "!!!") +except KeyError: + pass +else: + print("Failed to raise KeyError") + diff --git a/tests/basics/tests/set_remove.py b/tests/basics/tests/set_remove.py new file mode 100644 index 0000000000..208ab137f3 --- /dev/null +++ b/tests/basics/tests/set_remove.py @@ -0,0 +1,9 @@ +s = {1} +print(s.remove(1)) +print(list(s)) +try: + print(s.remove(1), "!!!") +except KeyError: + pass +else: + print("failed to raise KeyError") diff --git a/tests/basics/tests/set_symmetric_difference.py b/tests/basics/tests/set_symmetric_difference.py new file mode 100644 index 0000000000..acf298385a --- /dev/null +++ b/tests/basics/tests/set_symmetric_difference.py @@ -0,0 +1,7 @@ +print({1,2}.symmetric_difference({2,3})) +print({1,2}.symmetric_difference([2,3])) +s = {1,2} +print(s.symmetric_difference_update({2,3})) +l = list(s) +l.sort() +print(l) diff --git a/tests/basics/tests/set_union.py b/tests/basics/tests/set_union.py new file mode 100644 index 0000000000..2adcc972c0 --- /dev/null +++ b/tests/basics/tests/set_union.py @@ -0,0 +1 @@ +print({1}.union({2})) diff --git a/tests/basics/tests/set_update.py b/tests/basics/tests/set_update.py new file mode 100644 index 0000000000..78cd763560 --- /dev/null +++ b/tests/basics/tests/set_update.py @@ -0,0 +1,12 @@ +def report(s): + l = list(s) + l.sort() + print(l) + +s = {1} +s.update() +report(s) +s.update([2]) +report(s) +s.update([1,3], [2,2,4]) +report(s) diff --git a/tests/basics/tests/string_find.py b/tests/basics/tests/string_find.py new file mode 100644 index 0000000000..90063228f8 --- /dev/null +++ b/tests/basics/tests/string_find.py @@ -0,0 +1,11 @@ +print("hello world".find("ll")) +print("hello world".find("ll", None)) +print("hello world".find("ll", 1)) +print("hello world".find("ll", 1, None)) +print("hello world".find("ll", None, None)) +print("hello world".find("ll", 1, -1)) +print("hello world".find("ll", 1, 1)) +print("hello world".find("ll", 1, 2)) +print("hello world".find("ll", 1, 3)) +print("hello world".find("ll", 1, 4)) +print("hello world".find("ll", 1, 5)) |