diff options
67 files changed, 776 insertions, 315 deletions
diff --git a/py/builtinimport.c b/py/builtinimport.c index e6bb7586c8..e758158a64 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/compile.c b/py/compile.c index 36ffa928ee..cdd3a5b030 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1147,7 +1147,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_ qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]); if (attr == MP_QSTR_bytecode) { - *emit_options = MP_EMIT_OPT_BYTE_CODE; + *emit_options = MP_EMIT_OPT_BYTECODE; #if MICROPY_EMIT_NATIVE } else if (attr == MP_QSTR_native) { *emit_options = MP_EMIT_OPT_NATIVE_PYTHON; diff --git a/py/compile.h b/py/compile.h index 4606378976..52c42aff4f 100644 --- a/py/compile.h +++ b/py/compile.h @@ -27,7 +27,7 @@ // These must fit in 8 bits; see scope.h enum { MP_EMIT_OPT_NONE, - MP_EMIT_OPT_BYTE_CODE, + MP_EMIT_OPT_BYTECODE, MP_EMIT_OPT_NATIVE_PYTHON, MP_EMIT_OPT_VIPER, MP_EMIT_OPT_ASM_THUMB, diff --git a/py/emitglue.c b/py/emitglue.c index 7265a206a8..528c3bd36c 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -49,24 +49,6 @@ #define DEBUG_OP_printf(...) (void)0 #endif -#ifdef WRITE_CODE -FILE *fp_write_code = NULL; -#endif - -void mp_emit_glue_init(void) { -#ifdef WRITE_CODE - fp_write_code = fopen("out-code", "wb"); -#endif -} - -void mp_emit_glue_deinit(void) { -#ifdef WRITE_CODE - if (fp_write_code != NULL) { - fclose(fp_write_code); - } -#endif -} - mp_raw_code_t *mp_emit_glue_new_raw_code(void) { mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); rc->kind = MP_CODE_RESERVED; @@ -123,10 +105,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void DEBUG_printf("\n"); #ifdef WRITE_CODE - if (fp_write_code != NULL) { - fwrite(fun_data, len, 1, fp_write_code); - fflush(fp_write_code); - } + FILE *fp_write_code = fopen("out-code", "wb"); + fwrite(fun_data, len, 1, fp_write_code); + fclose(fp_write_code); #endif #endif } diff --git a/py/emitglue.h b/py/emitglue.h index 43bfb5e08a..c6cbb6283d 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -52,9 +52,6 @@ typedef struct _mp_code_t { }; } mp_raw_code_t; -void mp_emit_glue_init(void); -void mp_emit_glue_deinit(void); - mp_raw_code_t *mp_emit_glue_new_raw_code(void); void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags); diff --git a/py/lexer.c b/py/lexer.c index f736ef3030..e2dfea78c8 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -64,6 +64,13 @@ struct _mp_lexer_t { mp_token_t tok_cur; }; +// debug flag for __debug__ constant +STATIC mp_token_kind_t mp_debug_value; + +void mp_set_debug(bool value) { + mp_debug_value = value ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE; +} + // TODO replace with a call to a standard function bool str_strn_equal(const char *str, const char *strn, int len) { uint i = 0; @@ -303,7 +310,7 @@ STATIC const char *tok_kw[] = { "while", "with", "yield", - NULL, + "__debug__", }; STATIC int hex_digit(unichar c) { @@ -687,9 +694,18 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs // check for keywords if (tok->kind == MP_TOKEN_NAME) { - for (int i = 0; tok_kw[i] != NULL; i++) { + // We check for __debug__ here and convert it to its value. This is so + // the parser gives a syntax error on, eg, x.__debug__. Otherwise, we + // need to check for this special token in many places in the compiler. + // TODO improve speed of these string comparisons + //for (int i = 0; tok_kw[i] != NULL; i++) { + for (int i = 0; i < ARRAY_SIZE(tok_kw); i++) { if (str_strn_equal(tok_kw[i], tok->str, tok->len)) { - tok->kind = MP_TOKEN_KW_FALSE + i; + if (i == ARRAY_SIZE(tok_kw) - 1) { + tok->kind = mp_debug_value; + } else { + tok->kind = MP_TOKEN_KW_FALSE + i; + } break; } } diff --git a/py/modio.c b/py/modio.c index 892d493c95..b1f0d880ae 100644 --- a/py/modio.c +++ b/py/modio.c @@ -32,13 +32,24 @@ #if MICROPY_ENABLE_MOD_IO +extern const mp_obj_type_t mp_type_fileio; +extern const mp_obj_type_t mp_type_textio; + STATIC const mp_map_elem_t mp_module_io_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_io) }, // Note: mp_builtin_open_obj should be defined by port, it's not // part of the core. { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_stringio }, + #if MICROPY_MOD_IO_FILEIO + { MP_OBJ_NEW_QSTR(MP_QSTR_FileIO), (mp_obj_t)&mp_type_fileio }, + #endif + #if MICROPY_CPYTHON_COMPAT + { MP_OBJ_NEW_QSTR(MP_QSTR_TextIOWrapper), (mp_obj_t)&mp_type_textio }, + #endif { MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio }, + #if MICROPY_IO_BYTESIO + { MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio }, + #endif }; STATIC const mp_obj_dict_t mp_module_io_globals = { diff --git a/py/modstruct.c b/py/modstruct.c index b53dd51836..19cf9cfd6c 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +35,7 @@ #include "objtuple.h" #include "objstr.h" #include "binary.h" +#include "parsenum.h" #if MICROPY_ENABLE_MOD_STRUCT @@ -56,9 +58,26 @@ STATIC char get_fmt_type(const char **fmt) { return t; } +STATIC machine_uint_t get_fmt_num(const char **p) { + const char *num = *p; + uint len = 1; + while (unichar_isdigit(*++num)) { + len++; + } + machine_uint_t val = (machine_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10)); + *p = num; + return val; +} + STATIC uint calcsize_items(const char *fmt) { - // TODO - return strlen(fmt); + uint cnt = 0; + while (*fmt) { + // TODO supports size spec only for "s" + if (!unichar_isdigit(*fmt++)) { + cnt++; + } + } + return cnt; } STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { @@ -66,10 +85,24 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { char fmt_type = get_fmt_type(&fmt); machine_uint_t size; for (size = 0; *fmt; fmt++) { - uint align; - int sz = mp_binary_get_size(fmt_type, *fmt, &align); + uint align = 1; + machine_uint_t cnt = 1; + if (unichar_isdigit(*fmt)) { + cnt = get_fmt_num(&fmt); + } + if (cnt > 1) { + // TODO: count spec support only for string len + assert(*fmt == 's'); + } + + machine_uint_t sz; + if (*fmt == 's') { + sz = cnt; + } else { + sz = (machine_uint_t)mp_binary_get_size(fmt_type, *fmt, &align); + } // TODO - assert(sz != -1); + assert(sz != (machine_uint_t)-1); // Apply alignment size = (size + align - 1) & ~(align - 1); size += sz; @@ -89,7 +122,22 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) { byte *p = bufinfo.buf; for (uint i = 0; i < size; i++) { - mp_obj_t item = mp_binary_get_val(fmt_type, *fmt++, &p); + machine_uint_t sz = 1; + if (unichar_isdigit(*fmt)) { + sz = get_fmt_num(&fmt); + } + if (sz > 1) { + // TODO: size spec support only for string len + assert(*fmt == 's'); + } + mp_obj_t item; + if (*fmt == 's') { + item = mp_obj_new_bytes(p, sz); + p += sz; + fmt++; + } else { + item = mp_binary_get_val(fmt_type, *fmt++, &p); + } res->items[i] = item; } return res; @@ -106,7 +154,29 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) { memset(p, 0, size); for (uint i = 1; i < n_args; i++) { - mp_binary_set_val(fmt_type, *fmt++, args[i], &p); + machine_uint_t sz = 1; + if (unichar_isdigit(*fmt)) { + sz = get_fmt_num(&fmt); + } + if (sz > 1) { + // TODO: size spec support only for string len + assert(*fmt == 's'); + } + + if (*fmt == 's') { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[i], &bufinfo, MP_BUFFER_READ); + machine_uint_t to_copy = sz; + if (bufinfo.len < to_copy) { + to_copy = bufinfo.len; + } + memcpy(p, bufinfo.buf, to_copy); + memset(p + to_copy, 0, sz - to_copy); + p += sz; + fmt++; + } else { + mp_binary_set_val(fmt_type, *fmt++, args[i], &p); + } } return res; } diff --git a/py/mpconfig.h b/py/mpconfig.h index 76cd1091cb..445fc78b04 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -225,6 +225,14 @@ typedef double mp_float_t; #define MICROPY_ENABLE_MOD_IO (1) #endif +#ifndef MICROPY_MOD_IO_FILEIO +#define MICROPY_MOD_IO_FILEIO (0) +#endif + +#ifndef MICROPY_IO_BYTESIO +#define MICROPY_IO_BYTESIO (1) +#endif + // Whether to provide "struct" module #ifndef MICROPY_ENABLE_MOD_STRUCT #define MICROPY_ENABLE_MOD_STRUCT (1) @@ -207,17 +207,15 @@ STATIC uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) { mpz_dig_t *oidig = idig; - jlen -= klen; - for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { *idig = *jdig & *kdig; } - for (; jlen > 0; --jlen, ++idig) { - *idig = 0; + // remove trailing zeros + for (--idig; idig >= oidig && *idig == 0; --idig) { } - return idig - oidig; + return idig + 1 - oidig; } /* computes i = j | k @@ -898,14 +896,15 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { can have dest, lhs, rhs the same */ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { - if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { + // make sure lhs has the most digits + if (lhs->len < rhs->len) { const mpz_t *temp = lhs; lhs = rhs; rhs = temp; } if (lhs->neg == rhs->neg) { - mpz_need_dig(dest, lhs->len); + mpz_need_dig(dest, rhs->len); dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } else { mpz_need_dig(dest, lhs->len); @@ -122,7 +122,7 @@ int mp_obj_is_true(mp_obj_t arg) { mp_obj_type_t *type = mp_obj_get_type(arg); if (type->unary_op != NULL) { mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg); - if (result != MP_OBJ_NOT_SUPPORTED) { + if (result != MP_OBJ_NULL) { return result == mp_const_true; } } @@ -212,7 +212,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { mp_obj_type_t *type = mp_obj_get_type(o1); if (type->binary_op != NULL) { mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); - if (r != MP_OBJ_NOT_SUPPORTED) { + if (r != MP_OBJ_NULL) { return r == mp_const_true ? true : false; } } @@ -222,7 +222,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { return false; } -machine_int_t mp_obj_get_int(mp_obj_t arg) { +machine_int_t mp_obj_get_int(mp_const_obj_t arg) { // This function essentially performs implicit type conversion to int // Note that Python does NOT provide implicit type conversion from // float to int in the core expression language, try some_list[1.0]. @@ -242,7 +242,7 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) { // returns false if arg is not of integral type // returns true and sets *value if it is of integral type // can throw OverflowError if arg is of integral type, but doesn't fit in a machine_int_t -bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) { +bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value) { if (arg == mp_const_false) { *value = 0; } else if (arg == mp_const_true) { @@ -357,12 +357,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { } else { mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->unary_op != NULL) { - mp_obj_t val = type->unary_op(MP_UNARY_OP_LEN, o_in); - // TODO: Here's the case of having MP_OBJ_NOT_SUPPORTED is confusing - if (val == MP_OBJ_NOT_SUPPORTED) { - return MP_OBJ_NULL; - } - return val; + return type->unary_op(MP_UNARY_OP_LEN, o_in); } else { return MP_OBJ_NULL; } @@ -373,7 +368,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { mp_obj_type_t *type = mp_obj_get_type(base); if (type->subscr != NULL) { mp_obj_t ret = type->subscr(base, index, value); - if (ret != MP_OBJ_NOT_SUPPORTED) { + if (ret != MP_OBJ_NULL) { return ret; } // TODO: call base classes here? @@ -52,8 +52,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // These fake objects are used to indicate certain things in arguments or return // values, and should only be used when explicitly allowed. // -// - MP_OBJ_NULL : used to indicate the absence of an object. -// - MP_OBJ_NOT_SUPPORTED : a return value that indicates an unsupported operation. +// - MP_OBJ_NULL : used to indicate the absence of an object, or unsupported operation. // - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency. // - MP_OBJ_SENTINEL : used for various internal purposes where one needs // an object which is unique from all other objects, including MP_OBJ_NULL. @@ -63,14 +62,12 @@ typedef struct _mp_obj_base_t mp_obj_base_t; #if NDEBUG #define MP_OBJ_NULL ((mp_obj_t)0) -#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)0) #define MP_OBJ_STOP_ITERATION ((mp_obj_t)0) #define MP_OBJ_SENTINEL ((mp_obj_t)4) #else #define MP_OBJ_NULL ((mp_obj_t)0) -#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)4) -#define MP_OBJ_STOP_ITERATION ((mp_obj_t)8) -#define MP_OBJ_SENTINEL ((mp_obj_t)12) +#define MP_OBJ_STOP_ITERATION ((mp_obj_t)4) +#define MP_OBJ_SENTINEL ((mp_obj_t)8) #endif // These macros check for small int, qstr or object, and access small int and qstr values @@ -158,7 +155,7 @@ typedef enum _mp_map_lookup_kind_t { MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2 } mp_map_lookup_kind_t; -static inline bool MP_MAP_SLOT_IS_FILLED(mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); } +static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); } void mp_map_init(mp_map_t *map, int n); void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table); @@ -177,7 +174,7 @@ typedef struct _mp_set_t { mp_obj_t *table; } mp_set_t; -static inline bool MP_SET_SLOT_IS_FILLED(mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); } +static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); } void mp_set_init(mp_set_t *set, int n); mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); @@ -246,6 +243,7 @@ typedef struct _mp_stream_p_t { machine_int_t (*read)(mp_obj_t obj, void *buf, machine_uint_t size, int *errcode); machine_int_t (*write)(mp_obj_t obj, const void *buf, machine_uint_t size, int *errcode); // add seek() ? + int is_bytes : 1; } mp_stream_p_t; struct _mp_obj_type_t { @@ -255,15 +253,15 @@ struct _mp_obj_type_t { mp_make_new_fun_t make_new; // to make an instance of the type mp_call_fun_t call; - mp_unary_op_fun_t unary_op; // can return MP_OBJ_NOT_SUPPORTED if op not supported - mp_binary_op_fun_t binary_op; // can return MP_OBJ_NOT_SUPPORTED if op not supported + mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported + mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported mp_load_attr_fun_t load_attr; mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute mp_subscr_fun_t subscr; // implements load, store, delete subscripting // value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store - // can return MP_OBJ_NOT_SUPPORTED + // can return MP_OBJ_NULL if op not supported mp_fun_1_t getiter; mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args) @@ -321,6 +319,7 @@ extern const mp_obj_type_t mp_type_staticmethod; extern const mp_obj_type_t mp_type_classmethod; extern const mp_obj_type_t mp_type_property; extern const mp_obj_type_t mp_type_stringio; +extern const mp_obj_type_t mp_type_bytesio; // Exceptions extern const mp_obj_type_t mp_type_BaseException; @@ -422,8 +421,8 @@ bool mp_obj_is_callable(mp_obj_t o_in); machine_int_t mp_obj_hash(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); -machine_int_t mp_obj_get_int(mp_obj_t arg); -bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value); +machine_int_t mp_obj_get_int(mp_const_obj_t arg); +bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value); #if MICROPY_ENABLE_FLOAT mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); @@ -450,7 +449,7 @@ machine_int_t mp_obj_int_get(mp_obj_t self_in); mp_float_t mp_obj_int_as_float(mp_obj_t self_in); #endif // Will raise exception if value doesn't fit into machine_int_t -machine_int_t mp_obj_int_get_checked(mp_obj_t self_in); +machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in); // exception #define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new) @@ -481,11 +480,11 @@ typedef struct _mp_obj_float_t { mp_float_t value; } mp_obj_float_t; mp_float_t mp_obj_float_get(mp_obj_t self_in); -mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NOT_SUPPORTED +mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported // complex void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); -mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NOT_SUPPORTED +mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported #endif // tuple @@ -538,7 +537,7 @@ typedef struct _mp_obj_fun_native_t { // need this so we can define const object bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args, uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2); -const char *mp_obj_fun_get_name(mp_obj_t fun); +const char *mp_obj_fun_get_name(mp_const_obj_t fun); const char *mp_obj_code_get_name(const byte *code_info); mp_obj_t mp_identity(mp_obj_t self); diff --git a/py/objarray.c b/py/objarray.c index b394d77461..d973a4c563 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -139,7 +140,7 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) { switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -165,7 +166,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value // TODO implement // TODO: confirmed that both bytearray and array.array support // slice deletion - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } else { mp_obj_array_t *o = self_in; if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { @@ -173,7 +174,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value // Only getting a slice is suported so far, not assignment // TODO: confirmed that both bytearray and array.array support // slice assignment (incl. of different size) - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } machine_uint_t start, stop; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &start, &stop)) { diff --git a/py/objbool.c b/py/objbool.c index e31e7a2a42..4fe7a19341 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -76,7 +76,7 @@ STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) { return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in); } - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } const mp_obj_type_t mp_type_bool = { diff --git a/py/objcomplex.c b/py/objcomplex.c index 18e0edc519..80a13c6d8f 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -123,7 +123,7 @@ STATIC mp_obj_t complex_unary_op(int op, mp_obj_t o_in) { case MP_UNARY_OP_BOOL: return MP_BOOL(o->real != 0 || o->imag != 0); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -233,7 +233,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im case MP_BINARY_OP_EQUAL: return MP_BOOL(lhs_real == rhs_real && lhs_imag == rhs_imag); default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } return mp_obj_new_complex(lhs_real, lhs_imag); } diff --git a/py/objdict.c b/py/objdict.c index 9d4ebb6279..f41eacd939 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -103,7 +103,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) { switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->map.used); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -140,7 +140,7 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } default: // op not supported - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; } } @@ -463,13 +463,13 @@ STATIC void dict_view_print(void (*print)(void *env, const char *fmt, ...), void } STATIC mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { - /* only supported for the 'keys' kind until sets and dicts are refactored */ + // only supported for the 'keys' kind until sets and dicts are refactored mp_obj_dict_view_t *o = lhs_in; if (o->kind != MP_DICT_VIEW_KEYS) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } if (op != MP_BINARY_OP_IN) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } return dict_binary_op(op, o->dict, rhs_in); } diff --git a/py/objexcept.c b/py/objexcept.c index 7f5f9c73d2..0006554a85 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -120,12 +120,27 @@ STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } +STATIC mp_obj_t exc___init__(uint n_args, const mp_obj_t *args) { + mp_obj_exception_t *self = args[0]; + mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1); + self->args = argst; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__); + +STATIC const mp_map_elem_t exc_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&exc___init___obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table); + const mp_obj_type_t mp_type_BaseException = { { &mp_type_type }, .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, .load_attr = exception_load_attr, + .locals_dict = (mp_obj_t)&exc_locals_dict, }; #define MP_DEFINE_EXCEPTION_BASE(base_name) \ diff --git a/py/objfloat.c b/py/objfloat.c index e27942143d..6732f31215 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -96,7 +96,7 @@ STATIC mp_obj_t float_unary_op(int op, mp_obj_t o_in) { case MP_UNARY_OP_BOOL: return MP_BOOL(o->value != 0); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-o->value); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -165,7 +165,7 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) { case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } return mp_obj_new_float(lhs_val); } diff --git a/py/objfun.c b/py/objfun.c index 732009376d..26dfe0b2e2 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,7 +59,7 @@ STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // we don't even need to check for 2nd arg type. return MP_BOOL(lhs_in == rhs_in); } - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { @@ -153,8 +154,8 @@ const char *mp_obj_code_get_name(const byte *code_info) { return qstr_str(block_name); } -const char *mp_obj_fun_get_name(mp_obj_t fun_in) { - mp_obj_fun_bc_t *fun = fun_in; +const char *mp_obj_fun_get_name(mp_const_obj_t fun_in) { + const mp_obj_fun_bc_t *fun = fun_in; const byte *code_info = fun->bytecode; return mp_obj_code_get_name(code_info); } diff --git a/py/objgenerator.c b/py/objgenerator.c index fb8366bae5..8180185b94 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -98,10 +99,6 @@ void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *en print(env, "<generator object '%s' at %p>", mp_obj_code_get_name(self->code_info), self_in); } -mp_obj_t gen_instance_getiter(mp_obj_t self_in) { - return self_in; -} - mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = self_in; @@ -250,7 +247,7 @@ const mp_obj_type_t mp_type_gen_instance = { { &mp_type_type }, .name = MP_QSTR_generator, .print = gen_instance_print, - .getiter = gen_instance_getiter, + .getiter = mp_identity, .iternext = gen_instance_iternext, .locals_dict = (mp_obj_t)&gen_instance_locals_dict, }; diff --git a/py/objint.c b/py/objint.c index d1d99a253f..a3b3554008 100644 --- a/py/objint.c +++ b/py/objint.c @@ -129,7 +129,7 @@ STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) // // The resulting formatted string will be returned from this function and the // formatted size will be in *fmt_size. -char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, +char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { fmt_int_t num; if (MP_OBJ_IS_SMALL_INT(self_in)) { @@ -216,7 +216,7 @@ bool mp_obj_int_is_positive(mp_obj_t self_in) { // This is called for operations on SMALL_INT that are not handled by mp_unary_op mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } // This is called for operations on SMALL_INT that are not handled by mp_binary_op @@ -258,7 +258,7 @@ machine_int_t mp_obj_int_get(mp_obj_t self_in) { return MP_OBJ_SMALL_INT_VALUE(self_in); } -machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) { +machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { return MP_OBJ_SMALL_INT_VALUE(self_in); } @@ -285,7 +285,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_ return mp_binary_op(op, rhs_in, lhs_in); } } - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } // this is a classmethod diff --git a/py/objint.h b/py/objint.h index 0ea19d0ddb..1d12cffae0 100644 --- a/py/objint.h +++ b/py/objint.h @@ -34,9 +34,9 @@ typedef struct _mp_obj_int_t { } mp_obj_int_t; void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind); -char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, +char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); -char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, +char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); bool mp_obj_int_is_positive(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index f648615a73..1e0167b464 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -63,7 +64,7 @@ mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val); case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -76,7 +77,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { lhs_val = ((mp_obj_int_t*)lhs_in)->val; } else { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } if (MP_OBJ_IS_SMALL_INT(rhs_in)) { @@ -134,7 +135,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return MP_BOOL(lhs_val == rhs_val); default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } @@ -185,7 +186,7 @@ machine_int_t mp_obj_int_get(mp_obj_t self_in) { } } -machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) { +machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { // TODO: Check overflow return mp_obj_int_get(self_in); } diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 8e72782d66..2df3232e9c 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -58,10 +58,10 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { // formatted size will be in *fmt_size. // // This particular routine should only be called for the mpz representation of the int. -char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, +char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); - mp_obj_int_t *self = self_in; + const mp_obj_int_t *self = self_in; uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma); if (needed_size > *buf_size) { @@ -90,7 +90,7 @@ mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return o2; } case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return o2; } - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -108,7 +108,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { zlhs = &((mp_obj_int_t*)lhs_in)->mpz; } else { // unsupported type - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; } // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) @@ -213,7 +213,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { break; default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } return res; @@ -233,7 +233,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return MP_BOOL(cmp == 0); default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } } @@ -284,11 +284,11 @@ machine_int_t mp_obj_int_get(mp_obj_t self_in) { } } -machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) { +machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { if (MP_OBJ_IS_SMALL_INT(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); } else { - mp_obj_int_t *self = self_in; + const mp_obj_int_t *self = self_in; machine_int_t value; if (mpz_as_int_checked(&self->mpz, &value)) { return value; diff --git a/py/objlist.c b/py/objlist.c index 0ef685daeb..ee74926923 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -103,7 +103,7 @@ STATIC mp_obj_t list_unary_op(int op, mp_obj_t self_in) { switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(self->len != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -112,7 +112,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case MP_BINARY_OP_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } mp_obj_list_t *p = rhs; mp_obj_list_t *s = list_new(o->len + p->len); @@ -121,7 +121,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } case MP_BINARY_OP_INPLACE_ADD: { if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } list_extend(lhs, rhs); return o; @@ -129,7 +129,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_MULTIPLY: { machine_int_t n; if (!mp_obj_get_int_maybe(rhs, &n)) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); @@ -143,7 +143,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return MP_BOOL(list_cmp_helper(op, lhs, rhs)); default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } diff --git a/py/objmap.c b/py/objmap.c index 232e611bd2..6e5c79017d 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -56,10 +56,6 @@ STATIC mp_obj_t map_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ return o; } -STATIC mp_obj_t map_getiter(mp_obj_t self_in) { - return self_in; -} - STATIC mp_obj_t map_iternext(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); mp_obj_map_t *self = self_in; @@ -80,6 +76,6 @@ const mp_obj_type_t mp_type_map = { { &mp_type_type }, .name = MP_QSTR_map, .make_new = map_make_new, - .getiter = map_getiter, + .getiter = mp_identity, .iternext = map_iternext, }; diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 212cf131c8..a55dd643b0 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/py/objnone.c b/py/objnone.c index bb4e7e5608..165c8e5a43 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -44,7 +44,7 @@ STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env STATIC mp_obj_t none_unary_op(int op, mp_obj_t o_in) { switch (op) { case MP_UNARY_OP_BOOL: return mp_const_false; - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } diff --git a/py/objset.c b/py/objset.c index a6f1fe7339..32c194db12 100644 --- a/py/objset.c +++ b/py/objset.c @@ -475,7 +475,7 @@ STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) { switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(self->set.used != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->set.used); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -514,7 +514,7 @@ STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return MP_BOOL(elem != NULL); } default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } diff --git a/py/objstr.c b/py/objstr.c index 79ad891d05..61fda12a3f 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,6 +38,7 @@ #include "runtime.h" #include "pfenv.h" #include "objstr.h" +#include "objlist.h" STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args); const mp_obj_t mp_const_empty_bytes; @@ -52,7 +54,7 @@ const mp_obj_t mp_const_empty_bytes; STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str); STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str); -STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len); +mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len); STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); STATIC NORETURN void arg_type_mixup(); @@ -294,7 +296,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_MULTIPLY: { if (!MP_OBJ_IS_SMALL_INT(rhs_in)) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } int n = MP_OBJ_SMALL_INT_VALUE(rhs_in); byte *data; @@ -326,9 +328,20 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len)); } + if (lhs_type == &mp_type_bytes) { + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) { + goto uncomparable; + } + return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, bufinfo.buf, bufinfo.len)); + } +uncomparable: + if (op == MP_BINARY_OP_EQUAL) { + return mp_const_false; + } } - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { @@ -352,7 +365,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return mp_obj_new_str(self_data + index_val, 1, true); } } else { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } @@ -482,6 +495,69 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) { return res; } +STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) { + if (n_args < 3) { + // If we don't have split limit, it doesn't matter from which side + // we split. + return str_split(n_args, args); + } + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + mp_obj_t sep = args[1]; + GET_STR_DATA_LEN(args[0], s, len); + + machine_int_t splits = mp_obj_get_int(args[2]); + machine_int_t org_splits = splits; + // Preallocate list to the max expected # of elements, as we + // will fill it from the end. + mp_obj_list_t *res = mp_obj_new_list(splits + 1, NULL); + int idx = splits; + + if (sep == mp_const_none) { + // TODO + assert(0); + } else { + uint sep_len; + const char *sep_str = mp_obj_str_get_data(sep, &sep_len); + + if (sep_len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator")); + } + + const byte *beg = s; + const byte *last = s + len; + for (;;) { + s = last - sep_len; + for (;;) { + if (splits == 0 || s < beg) { + break; + } else if (memcmp(s, sep_str, sep_len) == 0) { + break; + } + s--; + } + if (s < beg || splits == 0) { + res->items[idx] = str_new(self_type, beg, last - beg); + break; + } + res->items[idx--] = str_new(self_type, s + sep_len, last - s - sep_len); + last = s; + if (splits > 0) { + splits--; + } + } + if (idx != 0) { + // We split less parts than split limit, now go cleanup surplus + int used = org_splits + 1 - idx; + memcpy(res->items, &res->items[idx], used * sizeof(mp_obj_t)); + mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items)); + res->len = used; + } + } + + return res; +} + + STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction, bool is_index) { assert(2 <= n_args && n_args <= 4); assert(MP_OBJ_IS_STR(args[0])); @@ -530,13 +606,17 @@ STATIC mp_obj_t str_rindex(uint n_args, const mp_obj_t *args) { } // TODO: (Much) more variety in args -STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) { - GET_STR_DATA_LEN(self_in, str, str_len); - GET_STR_DATA_LEN(arg, prefix, prefix_len); - if (prefix_len > str_len) { +STATIC mp_obj_t str_startswith(uint n_args, const mp_obj_t *args) { + GET_STR_DATA_LEN(args[0], str, str_len); + GET_STR_DATA_LEN(args[1], prefix, prefix_len); + uint index_val = 0; + if (n_args > 2) { + index_val = mp_get_index(&mp_type_str, str_len, args[2], true); + } + if (prefix_len + index_val > str_len) { return mp_const_false; } - return MP_BOOL(memcmp(str, prefix, prefix_len) == 0); + return MP_BOOL(memcmp(str + index_val, prefix, prefix_len) == 0); } enum { LSTRIP, RSTRIP, STRIP }; @@ -1459,7 +1539,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex); STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); @@ -1482,6 +1563,7 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_rindex), (mp_obj_t)&str_rindex_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_join), (mp_obj_t)&str_join_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t)&str_split_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rsplit), (mp_obj_t)&str_rsplit_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_startswith), (mp_obj_t)&str_startswith_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_strip), (mp_obj_t)&str_strip_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_lstrip), (mp_obj_t)&str_lstrip_obj }, @@ -1545,7 +1627,7 @@ mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) { return o; } -STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) { +mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) { mp_obj_str_t *o = m_new_obj(mp_obj_str_t); o->base.type = type; o->len = len; diff --git a/py/objstr.h b/py/objstr.h index 019f56f7b3..c0ef701a83 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -36,3 +36,4 @@ typedef struct _mp_obj_str_t { #define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str}; mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args); +mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len); diff --git a/py/objstringio.c b/py/objstringio.c index 880d4e1177..a1a765f89c 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +35,7 @@ #include "obj.h" #include "runtime.h" #include "stream.h" +#include "objstr.h" #if MICROPY_ENABLE_MOD_IO @@ -46,7 +48,7 @@ typedef struct _mp_obj_stringio_t { STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_stringio_t *self = self_in; - print(env, "<io.StringIO 0x%x>", self->vstr); + print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr); } STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { @@ -77,9 +79,11 @@ STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint return size; } +#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes) + STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { mp_obj_stringio_t *self = self_in; - return mp_obj_new_str((byte*)self->vstr->buf, self->vstr->len, false); + return str_new(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); @@ -96,16 +100,16 @@ mp_obj_t stringio___exit__(uint n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__); -STATIC mp_obj_stringio_t *stringio_new() { +STATIC mp_obj_stringio_t *stringio_new(mp_obj_t type_in) { mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); - o->base.type = &mp_type_stringio; + o->base.type = type_in; o->vstr = vstr_new(); o->pos = 0; return o; } STATIC mp_obj_t stringio_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { - mp_obj_stringio_t *o = stringio_new(); + mp_obj_stringio_t *o = stringio_new(type_in); if (n_args > 0) { mp_buffer_info_t bufinfo; @@ -135,6 +139,12 @@ STATIC const mp_stream_p_t stringio_stream_p = { .write = stringio_write, }; +STATIC const mp_stream_p_t bytesio_stream_p = { + .read = stringio_read, + .write = stringio_write, + .is_bytes = true, +}; + const mp_obj_type_t mp_type_stringio = { { &mp_type_type }, .name = MP_QSTR_StringIO, @@ -146,4 +156,17 @@ const mp_obj_type_t mp_type_stringio = { .locals_dict = (mp_obj_t)&stringio_locals_dict, }; +#if MICROPY_IO_BYTESIO +const mp_obj_type_t mp_type_bytesio = { + { &mp_type_type }, + .name = MP_QSTR_BytesIO, + .print = stringio_print, + .make_new = stringio_make_new, + .getiter = mp_identity, + .iternext = mp_stream_unbuffered_iter, + .stream_p = &bytesio_stream_p, + .locals_dict = (mp_obj_t)&stringio_locals_dict, +}; +#endif + #endif diff --git a/py/objtuple.c b/py/objtuple.c index 44ee95dd96..46515378f0 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -120,7 +120,7 @@ mp_obj_t mp_obj_tuple_unary_op(int op, mp_obj_t self_in) { switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(self->len != 0); case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); - default: return MP_OBJ_NOT_SUPPORTED; + default: return MP_OBJ_NULL; // op not supported } } @@ -129,7 +129,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case MP_BINARY_OP_ADD: { if (!mp_obj_is_subclass_fast(mp_obj_get_type(rhs), (mp_obj_t)&mp_type_tuple)) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } mp_obj_tuple_t *p = rhs; mp_obj_tuple_t *s = mp_obj_new_tuple(o->len + p->len, NULL); @@ -138,7 +138,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } case MP_BINARY_OP_MULTIPLY: { if (!MP_OBJ_IS_SMALL_INT(rhs)) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } int n = MP_OBJ_SMALL_INT_VALUE(rhs); mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL); @@ -153,8 +153,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return MP_BOOL(tuple_cmp_helper(op, lhs, rhs)); default: - // op not supported - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } @@ -176,7 +175,7 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { uint index_value = mp_get_index(self->base.type, self->len, index, false); return self->items[index_value]; } else { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } diff --git a/py/objtype.c b/py/objtype.c index 5f3e1db5d3..2e1c56416e 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -48,8 +49,10 @@ /******************************************************************************/ // instance object +#define is_instance_type(type) ((type)->make_new == instance_make_new) #define is_native_type(type) ((type)->make_new != instance_make_new) STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args); +STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) { mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); @@ -119,10 +122,10 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type, if (elem != NULL) { dest[0] = elem->value; if (o != MP_OBJ_NULL && is_native_type(type)) { - dest[1] = o->subobj[0]; + instance_convert_return_attr(o->subobj[0], type, elem->value, dest); + } else { + instance_convert_return_attr(o, type, elem->value, dest); } - // TODO: Sensibly, we should call instance_convert_return_attr() here, - // instead of multiple places later. Also, this code duplicates runtime.c much. return; } } @@ -215,38 +218,56 @@ STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, cons mp_obj_instance_t *o = mp_obj_new_instance(self_in, num_native_bases); - // look for __init__ function + // look for __new__ function mp_obj_t init_fn[2] = {MP_OBJ_NULL}; - mp_obj_class_lookup(NULL, self, MP_QSTR___init__, offsetof(mp_obj_type_t, make_new), init_fn); + mp_obj_class_lookup(NULL, self, MP_QSTR___new__, offsetof(mp_obj_type_t, make_new), init_fn); + mp_obj_t new_ret = o; if (init_fn[0] == MP_OBJ_SENTINEL) { // Native type's constructor is what wins - it gets all our arguments, // and none Python classes are initialized at all. o->subobj[0] = native_base->make_new((mp_obj_type_t*)native_base, n_args, n_kw, args); } else if (init_fn[0] != MP_OBJ_NULL) { - // We need to default-initialize any native subobjs first - if (num_native_bases > 0) { - o->subobj[0] = native_base->make_new((mp_obj_type_t*)native_base, 0, 0, NULL); - } - // now call Python class __init__ function with all args - mp_obj_t init_ret; + // now call Python class __new__ function with all args if (n_args == 0 && n_kw == 0) { - init_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&o); + new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&self_in); } else { mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw); - args2[0] = o; + args2[0] = self_in; memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); - init_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2); + new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2); m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); } + + } + + // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ + // "If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked." + if (mp_obj_get_type(new_ret) != self_in) { + return new_ret; + } + + o = new_ret; + + // now call Python class __init__ function with all args + init_fn[0] = init_fn[1] = NULL; + mp_obj_class_lookup(o, self, MP_QSTR___init__, 0, init_fn); + if (init_fn[0] != MP_OBJ_NULL) { + mp_obj_t init_ret; + if (n_args == 0 && n_kw == 0) { + init_ret = mp_call_method_n_kw(0, 0, init_fn); + } else { + mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw); + args2[0] = init_fn[0]; + args2[1] = init_fn[1]; + memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); + init_ret = mp_call_method_n_kw(n_args, n_kw, args2); + m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw); + } if (init_ret != mp_const_none) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); } - } else { - if (n_args != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object() takes no parameters")); - } } return o; @@ -266,7 +287,7 @@ STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) { qstr op_name = unary_op_method_name[op]; /* Still try to lookup native slot if (op_name == 0) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; } */ mp_obj_t member[2] = {MP_OBJ_NULL}; @@ -276,7 +297,7 @@ STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) { } else if (member[0] != MP_OBJ_NULL) { return mp_call_function_1(member[0], self_in); } else { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } @@ -324,7 +345,7 @@ STATIC const qstr binary_op_method_name[] = { // and put the result in the dest[] array for a possible method call. // Conversion means dealing with static/class methods, callables, and values. // see http://docs.python.org/3.3/howto/descriptor.html -STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_t *dest) { +STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) { assert(dest[1] == NULL); if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { // return just the function @@ -332,7 +353,7 @@ STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_ } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { // return a bound method, with self being the type of this object dest[0] = ((mp_obj_static_class_method_t*)member)->fun; - dest[1] = mp_obj_get_type(self); + dest[1] = (mp_obj_t)type; } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) { // Don't try to bind types dest[0] = member; @@ -353,26 +374,24 @@ STATIC mp_obj_t instance_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { qstr op_name = binary_op_method_name[op]; /* Still try to lookup native slot if (op_name == 0) { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; } */ - mp_obj_t member[2] = {MP_OBJ_NULL}; - mp_obj_class_lookup(lhs, lhs->base.type, op_name, offsetof(mp_obj_type_t, binary_op), member); - if (member[0] == MP_OBJ_SENTINEL) { + mp_obj_t dest[3] = {MP_OBJ_NULL}; + mp_obj_class_lookup(lhs, lhs->base.type, op_name, offsetof(mp_obj_type_t, binary_op), dest); + if (dest[0] == MP_OBJ_SENTINEL) { return mp_binary_op(op, lhs->subobj[0], rhs_in); - } else if (member[0] != MP_OBJ_NULL) { - mp_obj_t dest[3]; - dest[1] = MP_OBJ_NULL; - instance_convert_return_attr(lhs_in, member[0], dest); + } else if (dest[0] != MP_OBJ_NULL) { dest[2] = rhs_in; return mp_call_method_n_kw(1, 0, dest); } else { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // logic: look in obj members then class locals (TODO check this against CPython) + assert(is_instance_type(mp_obj_get_type(self_in))); mp_obj_instance_t *self = self_in; mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); @@ -386,9 +405,8 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_class_lookup(self, self->base.type, attr, 0, dest); mp_obj_t member = dest[0]; if (member != MP_OBJ_NULL) { - if (0) { #if MICROPY_ENABLE_PROPERTY - } else if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { + if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { // object member is a property // delegate the store to the property // TODO should this be part of instance_convert_return_attr? @@ -399,15 +417,8 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); // TODO should we convert the returned value using instance_convert_return_attr? } -#endif - } else { - // not a property - // if we don't yet have bound method (supposedly from native base), go - // try to convert own attrs. - if (dest[1] == MP_OBJ_NULL) { - instance_convert_return_attr(self_in, member, dest); - } } +#endif return; } @@ -488,7 +499,7 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value return mp_const_none; } } else { - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } @@ -515,7 +526,6 @@ STATIC mp_obj_t instance_getiter(mp_obj_t self_in) { mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, 0, member); if (member[0] != MP_OBJ_NULL) { // __getitem__ exists, create an iterator - instance_convert_return_attr(self_in, member[0], member); return mp_obj_new_getitem_iter(member); } return MP_OBJ_NULL; @@ -583,24 +593,7 @@ STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } #endif - mp_obj_t member[2] = {MP_OBJ_NULL}; - mp_obj_class_lookup(NULL, self, attr, 0, member); - if (member[0] != MP_OBJ_NULL) { - // check if the methods are functions, static or class methods - // see http://docs.python.org/3.3/howto/descriptor.html - if (MP_OBJ_IS_TYPE(member[0], &mp_type_staticmethod)) { - // return just the function - dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun; - } else if (MP_OBJ_IS_TYPE(member[0], &mp_type_classmethod)) { - // return a bound method, with self being this class - dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun; - dest[1] = self_in; - } else { - // return just the function - // TODO need to wrap in a type check for the first argument; eg list.append(1,1) needs to throw an exception - dest[0] = member[0]; - } - } + mp_obj_class_lookup(NULL, self, attr, 0, dest); } STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { @@ -639,7 +632,7 @@ STATIC mp_obj_t type_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return MP_BOOL(lhs_in == rhs_in); default: - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } } @@ -741,12 +734,7 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_tuple_get(type->bases_tuple, &len, &items); for (uint i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); - mp_obj_t member[2] = {MP_OBJ_NULL}; - mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, member); - if (member[0] != MP_OBJ_NULL) { - instance_convert_return_attr(self->obj, member[0], dest); - return; - } + mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, dest); } } diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 1679d8b39c..cffb64d5ef 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -34,6 +34,7 @@ Q(__class__) Q(__doc__) Q(__import__) Q(__init__) +Q(__new__) Q(__locals__) Q(__main__) Q(__module__) @@ -236,6 +237,7 @@ Q(find) Q(rfind) Q(rindex) Q(split) +Q(rsplit) Q(startswith) Q(replace) Q(partition) @@ -352,6 +354,8 @@ Q(io) Q(readall) Q(readline) Q(readlines) +Q(FileIO) +Q(TextIOWrapper) Q(StringIO) Q(BytesIO) Q(getvalue) diff --git a/py/runtime.c b/py/runtime.c index 8852b7d80d..ea75280ce4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -69,12 +69,13 @@ const mp_obj_module_t mp_module___main__ = { }; void mp_init(void) { - // call port specific initialization if any + // call port specific initialization if any #ifdef MICROPY_PORT_INIT_FUNC MICROPY_PORT_INIT_FUNC; #endif - mp_emit_glue_init(); + // __debug__ enabled by default + mp_set_debug(true); // init global module stuff mp_module_init(); @@ -90,7 +91,6 @@ void mp_init(void) { void mp_deinit(void) { //mp_obj_dict_free(&dict_main); mp_module_deinit(); - mp_emit_glue_deinit(); // call port specific deinitialization if any #ifdef MICROPY_PORT_INIT_FUNC @@ -200,7 +200,7 @@ mp_obj_t mp_unary_op(int op, mp_obj_t arg) { mp_obj_type_t *type = mp_obj_get_type(arg); if (type->unary_op != NULL) { mp_obj_t result = type->unary_op(op, arg); - if (result != MP_OBJ_NOT_SUPPORTED) { + if (result != MP_OBJ_NULL) { return result; } } @@ -439,7 +439,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_type_t *type = mp_obj_get_type(rhs); if (type->binary_op != NULL) { mp_obj_t res = type->binary_op(op, rhs, lhs); - if (res != MP_OBJ_NOT_SUPPORTED) { + if (res != MP_OBJ_NULL) { return res; } } @@ -467,7 +467,7 @@ generic_binary_op: type = mp_obj_get_type(lhs); if (type->binary_op != NULL) { mp_obj_t result = type->binary_op(op, lhs, rhs); - if (result != MP_OBJ_NOT_SUPPORTED) { + if (result != MP_OBJ_NULL) { return result; } } diff --git a/py/runtime.h b/py/runtime.h index 910a485446..a5d6743034 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -54,6 +54,8 @@ typedef struct _mp_arg_t { void mp_init(void); void mp_deinit(void); +void mp_set_debug(bool value); // sets the value of __debug__; see lexer.c + void mp_arg_check_num(uint n_args, uint n_kw, uint n_args_min, uint n_args_max, bool takes_kw); void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); void mp_arg_parse_all_kw_array(uint n_pos, uint n_kw, const mp_obj_t *args, uint n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); diff --git a/py/sequence.c b/py/sequence.c index 91162fc099..966adaac03 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -99,6 +100,10 @@ bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, u } uint min_len = len1 < len2 ? len1 : len2; int res = memcmp(data1, data2, min_len); + if (op == MP_BINARY_OP_EQUAL) { + // If we are checking for equality, here're the answer + return res == 0; + } if (res < 0) { return false; } diff --git a/py/stream.c b/py/stream.c index 9eb438b538..b1a64cdcf5 100644 --- a/py/stream.c +++ b/py/stream.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,6 +32,7 @@ #include "misc.h" #include "qstr.h" #include "obj.h" +#include "objstr.h" #include "stream.h" #if MICROPY_STREAMS_NON_BLOCK #include <errno.h> @@ -52,6 +54,8 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in); #define is_nonblocking_error(errno) (0) #endif +#define STREAM_CONTENT_TYPE(stream) (((stream)->is_bytes) ? &mp_type_bytes : &mp_type_str) + STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0]; if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) { @@ -77,7 +81,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) { } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); } else { - mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size + mp_obj_t s = str_new(STREAM_CONTENT_TYPE(o->type->stream_p), buf, out_sz); // will reallocate to use exact size m_free(buf, sz); return s; } @@ -154,7 +158,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { } } - mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, total_size, false); + mp_obj_t s = str_new(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, total_size); vstr_free(vstr); return s; } @@ -203,7 +207,7 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { } } // TODO need a string creation API that doesn't copy the given data - mp_obj_t ret = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); + mp_obj_t ret = str_new(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, vstr->len); vstr_free(vstr); return ret; } @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index 7f4c378901..76663ccabe 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -14,6 +14,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) #define MICROPY_PATH_MAX (512) +#define MICROPY_ENABLE_MOD_IO (0) // type definitions for the specific machine diff --git a/stmhal/dac.c b/stmhal/dac.c index f0f723f853..81ce993a8c 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -62,7 +62,7 @@ /// # create a buffer containing a sine-wave /// buf = bytearray(100) /// for i in range(len(buf)): -/// buf[i] = 128 + 127 * math.sin(2 * math.pi * i / len(buf)) +/// buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf))) /// /// # output the sine-wave at 400Hz /// dac = DAC(1) @@ -295,7 +295,11 @@ mp_obj_t pyb_dac_write_timed(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE; HAL_DMA_Init(&DMA_Handle); - __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle); + if (self->dac_channel == DAC_CHANNEL_1) { + __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle); + } else { + __HAL_LINKDMA(&DAC_Handle, DMA_Handle2, DMA_Handle); + } DAC_Handle.Instance = DAC; DAC_Handle.State = HAL_DAC_STATE_RESET; diff --git a/stmhal/file.c b/stmhal/file.c index 93bd49e669..3fea956530 100644 --- a/stmhal/file.c +++ b/stmhal/file.c @@ -41,7 +41,7 @@ typedef struct _pyb_file_obj_t { } pyb_file_obj_t; void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { - printf("<io.FileIO %p>", self_in); + printf("<io.%s %p>", mp_obj_get_type_str(self_in), self_in); } STATIC machine_int_t file_read(mp_obj_t self_in, void *buf, machine_uint_t size, int *errcode) { @@ -94,7 +94,7 @@ STATIC const mp_stream_p_t file_obj_stream_p = { .write = file_write, }; -STATIC const mp_obj_type_t file_obj_type = { +const mp_obj_type_t mp_type_textio = { { &mp_type_type }, .name = MP_QSTR_FileIO, .make_new = file_obj_make_new, @@ -113,7 +113,7 @@ STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, cons mode = mp_obj_str_get_str(args[1]); } pyb_file_obj_t *self = m_new_obj_with_finaliser(pyb_file_obj_t); - self->base.type = &file_obj_type; + self->base.type = &mp_type_textio; if (mode[0] == 'r') { // open for reading FRESULT res = f_open(&self->fp, filename, FA_READ); @@ -138,7 +138,7 @@ STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, cons // Factory function for I/O stream classes STATIC mp_obj_t pyb_io_open(uint n_args, const mp_obj_t *args) { // TODO: analyze mode and buffering args and instantiate appropriate type - return file_obj_make_new((mp_obj_t)&file_obj_type, n_args, 0, args); + return file_obj_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, pyb_io_open); diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 81dc921173..7ec25038bf 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -62,6 +62,23 @@ /// /// The `pyb` module contains specific functions related to the pyboard. +/// \function bootloader() +/// Activate the bootloader without BOOT* pins. +STATIC NORETURN mp_obj_t pyb_bootloader(void) { + pyb_usb_dev_stop(); + storage_flush(); + + HAL_RCC_DeInit(); + HAL_DeInit(); + + __HAL_REMAPMEMORY_SYSTEMFLASH(); + __set_MSP(*((uint32_t*) 0x00000000)); + ((void (*)(void)) *((uint32_t*) 0x00000004))(); + + while (1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_bootloader_obj, pyb_bootloader); + /// \function info([dump_alloc_table]) /// Print out lots of information about the board. STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) { @@ -302,6 +319,7 @@ MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); // defined in main.c STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_bootloader), (mp_obj_t)&pyb_bootloader_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj }, diff --git a/stmhal/modstm.c b/stmhal/modstm.c index e645af1229..520c8e51bd 100644 --- a/stmhal/modstm.c +++ b/stmhal/modstm.c @@ -81,7 +81,7 @@ STATIC mp_obj_t stm_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) stm_mem_obj_t *self = self_in; if (value == MP_OBJ_NULL) { // delete - return MP_OBJ_NOT_SUPPORTED; + return MP_OBJ_NULL; // op not supported } else if (value == MP_OBJ_SENTINEL) { // load uint32_t addr = get_read_addr(index, self->elem_size); diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index c2cf6840df..d822a542f0 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -29,6 +29,7 @@ Q(help) Q(pyb) Q(unique_id) +Q(bootloader) Q(info) Q(sd_test) Q(present) diff --git a/stmhal/usb.c b/stmhal/usb.c index fd8cbb95a1..ef7e8a62eb 100644 --- a/stmhal/usb.c +++ b/stmhal/usb.c @@ -75,6 +75,13 @@ void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium) { #endif } +void pyb_usb_dev_stop(void) { + if (dev_is_enabled) { + USBD_Stop(&hUSBDDevice); + dev_is_enabled = 0; + } +} + bool usb_vcp_is_enabled(void) { return dev_is_enabled; } diff --git a/stmhal/usb.h b/stmhal/usb.h index 8b8562ce6d..3bd30ba92c 100644 --- a/stmhal/usb.h +++ b/stmhal/usb.h @@ -42,6 +42,7 @@ typedef enum { } usb_storage_medium_t; void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium); +void pyb_usb_dev_stop(void); bool usb_vcp_is_enabled(void); bool usb_vcp_is_connected(void); void usb_vcp_set_interrupt_char(int c); diff --git a/tests/basics/bytes_compare.py b/tests/basics/bytes_compare.py index 3804844feb..292267ba75 100644 --- a/tests/basics/bytes_compare.py +++ b/tests/basics/bytes_compare.py @@ -49,3 +49,5 @@ print(b"1" <= b"10") print(b"1" <= b"1/") print(b"10" <= b"1") print(b"1/" <= b"1") + +print(b'o' == b'\n') diff --git a/tests/basics/bytes_compare2.py b/tests/basics/bytes_compare2.py new file mode 100644 index 0000000000..769d76b119 --- /dev/null +++ b/tests/basics/bytes_compare2.py @@ -0,0 +1,7 @@ +import array + +print(b"1" == 1) +print(b"123" == bytearray(b"123")) +print(b"123" == "123") +# CPyhon gives False here +#print(b"\x01\x02\x03" == array.array("B", [1, 2, 3])) diff --git a/tests/basics/int-big-and.py b/tests/basics/int-big-and.py new file mode 100644 index 0000000000..75fbd52884 --- /dev/null +++ b/tests/basics/int-big-and.py @@ -0,0 +1,8 @@ +print(0 & (1 << 80)) +print(0 & (1 << 80) == 0) +print(bool(0 & (1 << 80))) + +#a = 0xfffffffffffffffffffffffffffff +#print(a & (1 << 80)) +#print((a & (1 << 80)) >> 80) +#print((a & (1 << 80)) >> 80 == 1) diff --git a/tests/basics/int-long.py b/tests/basics/int-long.py index 3567e08b2d..a22075d1f9 100644 --- a/tests/basics/int-long.py +++ b/tests/basics/int-long.py @@ -11,7 +11,7 @@ print(b - a) #print(a * b) print(a // b) print(a % b) -print(a & b) +print("&", a & b) print(a | b) print(a ^ b) print(a << 3) @@ -32,7 +32,7 @@ print(a) a |= b print(a) a &= b -print(a) +print("&=", a) a <<= 5 print(a) a >>= 1 @@ -44,3 +44,11 @@ b = a a += 1 print(a) print(b) + +# Bitwise ops on 64-bit + +a = 0x1ffffffffffffffff +b = 0x10000000000000000 +print("&", a & b) +print(a | b) +print(a ^ b) diff --git a/tests/basics/string_rsplit.py b/tests/basics/string_rsplit.py new file mode 100644 index 0000000000..cc6c0fd062 --- /dev/null +++ b/tests/basics/string_rsplit.py @@ -0,0 +1,42 @@ +# default separator (whitespace) +print("a b".rsplit()) +#print(" a b ".rsplit(None)) +#print(" a b ".rsplit(None, 1)) +#print(" a b ".rsplit(None, 2)) +#print(" a b c ".rsplit(None, 1)) +#print(" a b c ".rsplit(None, 0)) +#print(" a b c ".rsplit(None, -1)) + +# empty separator should fail +try: + "abc".rsplit('') +except ValueError: + print("ValueError") + +# non-empty separator +print("abc".rsplit("a")) +print("abc".rsplit("b")) +print("abc".rsplit("c")) +print("abc".rsplit("z")) +print("abc".rsplit("ab")) +print("abc".rsplit("bc")) +print("abc".rsplit("abc")) +print("abc".rsplit("abcd")) +print("abcabc".rsplit("bc")) +print("abcabc".rsplit("bc", 0)) +print("abcabc".rsplit("bc", 1)) +print("abcabc".rsplit("bc", 2)) + +print("10/11/12".rsplit("/", 1)) +print("10/11/12".rsplit("/", 2)) +print("10/11/12".rsplit("/", 3)) +print("10/11/12".rsplit("/", 4)) +print("10/11/12".rsplit("/", 5)) + +print("/*10/*11/*12/*".rsplit("/*", 1)) +print("/*10/*11/*12/*".rsplit("/*", 2)) +print("/*10/*11/*12/*".rsplit("/*", 3)) +print("/*10/*11/*12/*".rsplit("/*", 4)) +print("/*10/*11/*12/*".rsplit("/*", 5)) + +print(b"abcabc".rsplit(b"bc", 2)) diff --git a/tests/basics/string_startswith.py b/tests/basics/string_startswith.py index 99d653efbb..5cf730c03c 100644 --- a/tests/basics/string_startswith.py +++ b/tests/basics/string_startswith.py @@ -3,3 +3,9 @@ print("foobar".startswith("Foo")) print("foobar".startswith("foo1")) print("foobar".startswith("foobar")) print("foobar".startswith("")) + +print("1foobar".startswith("foo", 1)) +print("1foo".startswith("foo", 1)) +print("1foo".startswith("1foo", 1)) +print("1fo".startswith("foo", 1)) +print("1fo".startswith("foo", 10)) diff --git a/tests/basics/struct1.py b/tests/basics/struct1.py index 3a05c85f0b..b114a789b5 100644 --- a/tests/basics/struct1.py +++ b/tests/basics/struct1.py @@ -16,3 +16,8 @@ print(struct.pack(">b", 1)) print(struct.pack("<bI", -128, 256)) print(struct.pack(">bI", -128, 256)) + +print(struct.calcsize("100sI")) +print(struct.calcsize("97sI")) +print(struct.unpack("<6sH", b"foo\0\0\0\x12\x34")) +print(struct.pack("<6sH", b"foo", 10000)) diff --git a/tests/basics/subclass-native2-list.py b/tests/basics/subclass-native2-list.py new file mode 100644 index 0000000000..9ad0b77ef6 --- /dev/null +++ b/tests/basics/subclass-native2-list.py @@ -0,0 +1,26 @@ +class Base1: + def __init__(self, *args): + print("Base1.__init__", args) + +class Clist1(Base1, list): + pass + +a = Clist1() +print(len(a)) +# Not compliant - list assignment should happen in list.__init__, which is not called +# because there's Base1.__init__, but we assign in list.__new__ +#a = Clist1([1, 2, 3]) +#print(len(a)) + +print("---") + +class Clist2(list, Base1): + pass + +# Not compliant - should call list.__init__, but we don't have it +#a = Clist2() +#print(len(a)) + +# Not compliant - should call list.__init__, but we don't have it +#a = Clist2([1, 2, 3]) +#print(len(a)) diff --git a/tests/basics/subclass-native2-tuple.py b/tests/basics/subclass-native2-tuple.py new file mode 100644 index 0000000000..9eb69e1575 --- /dev/null +++ b/tests/basics/subclass-native2-tuple.py @@ -0,0 +1,21 @@ +class Base1: + def __init__(self, *args): + print("Base1.__init__", args) + +class Ctuple1(Base1, tuple): + pass + +a = Ctuple1() +print(len(a)) +a = Ctuple1([1, 2, 3]) +print(len(a)) + +print("---") + +class Ctuple2(tuple, Base1): + pass + +a = Ctuple2() +print(len(a)) +a = Ctuple2([1, 2, 3]) +print(len(a)) diff --git a/tests/basics/subclass-native2.py b/tests/basics/subclass-native2.py deleted file mode 100644 index 749bf969cf..0000000000 --- a/tests/basics/subclass-native2.py +++ /dev/null @@ -1,37 +0,0 @@ -class Base1: - def __init__(self, *args): - print("Base1.__init__",args) - -class Clist1(Base1, list): - pass - -class Ctuple1(Base1, tuple): - pass - -a = Clist1() -print(len(a)) -a = Clist1([1, 2, 3]) -print(len(a)) - -a = Ctuple1() -print(len(a)) -a = Ctuple1([1, 2, 3]) -# TODO: Faults -#print(len(a)) - -print("---") - -class Clist2(list, Base1): - pass - -class Ctuple2(tuple, Base1): - pass -a = Clist2() -print(len(a)) -a = Clist2([1, 2, 3]) -print(len(a)) - -#a = Ctuple2() -#print(len(a)) -#a = Ctuple2([1, 2, 3]) -#print(len(a)) diff --git a/unix/Makefile b/unix/Makefile index ba2180fe58..b336892a42 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -68,6 +68,7 @@ SRC_C = \ input.c \ file.c \ modsocket.c \ + modos.c \ $(SRC_MOD) # Must be the last file diff --git a/unix/file.c b/unix/file.c index ada841ea2c..7f45ac4a33 100644 --- a/unix/file.c +++ b/unix/file.c @@ -54,11 +54,12 @@ void check_fd_is_open(const mp_obj_fdfile_t *o) { #define check_fd_is_open(o) #endif -STATIC const mp_obj_type_t rawfile_type; +extern const mp_obj_type_t mp_type_fileio; +extern const mp_obj_type_t mp_type_textio; STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_fdfile_t *self = self_in; - print(env, "<io.FileIO %d>", self->fd); + print(env, "<io.%s %d>", mp_obj_get_type_str(self), self->fd); } STATIC machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { @@ -103,23 +104,10 @@ STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); -STATIC mp_obj_fdfile_t *fdfile_new(int fd) { - mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t); - o->base.type = &rawfile_type; - o->fd = fd; - return o; -} - STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t); - o->base.type = type_in; - - if (MP_OBJ_IS_SMALL_INT(args[0])) { - o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]); - return o; - } + mp_const_obj_t type = type_in; - const char *fname = mp_obj_str_get_str(args[0]); const char *mode_s; if (n_args > 1) { mode_s = mp_obj_str_get_str(args[1]); @@ -143,14 +131,32 @@ STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const case '+': mode |= O_RDWR; break; + #if MICROPY_MOD_IO_FILEIO + // If we don't have io.FileIO, then files are in text mode implicitly + case 'b': + type = &mp_type_fileio; + break; + case 't': + type = &mp_type_textio; + break; + #endif } } + o->base.type = type; + + if (MP_OBJ_IS_SMALL_INT(args[0])) { + o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]); + return o; + } + + const char *fname = mp_obj_str_get_str(args[0]); int fd = open(fname, mode, 0644); if (fd == -1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno))); } - return fdfile_new(fd); + o->fd = fd; + return o; } STATIC const mp_map_elem_t rawfile_locals_dict_table[] = { @@ -167,29 +173,48 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); -STATIC const mp_stream_p_t rawfile_stream_p = { +#if MICROPY_MOD_IO_FILEIO +STATIC const mp_stream_p_t fileio_stream_p = { .read = fdfile_read, .write = fdfile_write, + .is_bytes = true, }; -STATIC const mp_obj_type_t rawfile_type = { +const mp_obj_type_t mp_type_fileio = { { &mp_type_type }, .name = MP_QSTR_FileIO, .print = fdfile_print, .make_new = fdfile_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &rawfile_stream_p, + .stream_p = &fileio_stream_p, + .locals_dict = (mp_obj_t)&rawfile_locals_dict, +}; +#endif + +STATIC const mp_stream_p_t textio_stream_p = { + .read = fdfile_read, + .write = fdfile_write, +}; + +const mp_obj_type_t mp_type_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = fdfile_print, + .make_new = fdfile_make_new, + .getiter = mp_identity, + .iternext = mp_stream_unbuffered_iter, + .stream_p = &textio_stream_p, .locals_dict = (mp_obj_t)&rawfile_locals_dict, }; // Factory function for I/O stream classes mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) { // TODO: analyze mode and buffering args and instantiate appropriate type - return fdfile_make_new((mp_obj_t)&rawfile_type, n_args, 0, args); + return fdfile_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open); -const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&rawfile_type}, .fd = STDIN_FILENO }; -const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&rawfile_type}, .fd = STDOUT_FILENO }; -const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&rawfile_type}, .fd = STDERR_FILENO }; +const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STDIN_FILENO }; +const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO }; +const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO }; diff --git a/unix/main.c b/unix/main.c index de296142b3..23dd4be631 100644 --- a/unix/main.c +++ b/unix/main.c @@ -69,9 +69,10 @@ void microsocket_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) { +// returns standard error codes: 0 for success, 1 for all other errors +STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { if (lex == NULL) { - return; + return 1; } if (0) { @@ -81,7 +82,7 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind mp_lexer_to_next(lex); } mp_lexer_free(lex); - return; + return 0; } mp_parse_error_kind_t parse_error_kind; @@ -91,7 +92,7 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind // parse error mp_parse_show_exception(lex, parse_error_kind); mp_lexer_free(lex); - return; + return 1; } qstr source_name = mp_lexer_source_name(lex); @@ -107,11 +108,11 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind if (module_fun == mp_const_none) { // compile error - return; + return 1; } if (compile_only) { - return; + return 0; } // execute it @@ -119,9 +120,11 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind if (nlr_push(&nlr) == 0) { mp_call_function_0(module_fun); nlr_pop(); + return 0; } else { // uncaught exception mp_obj_print_exception((mp_obj_t)nlr.ret_val); + return 1; } } @@ -165,14 +168,14 @@ STATIC void do_repl(void) { } } -STATIC void do_file(const char *file) { +STATIC int do_file(const char *file) { mp_lexer_t *lex = mp_lexer_new_from_file(file); - execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + return execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); } -STATIC void do_str(const char *str) { +STATIC int do_str(const char *str) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, str, strlen(str), false); - execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, false); + return execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, false); } int usage(char **argv) { @@ -230,7 +233,7 @@ void pre_process_options(int argc, char **argv) { } else if (strcmp(argv[a + 1], "compile-only") == 0) { compile_only = true; } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) { - emit_opt = MP_EMIT_OPT_BYTE_CODE; + emit_opt = MP_EMIT_OPT_BYTECODE; } else if (strcmp(argv[a + 1], "emit=native") == 0) { emit_opt = MP_EMIT_OPT_NATIVE_PYTHON; } else if (strcmp(argv[a + 1], "emit=viper") == 0) { @@ -321,20 +324,23 @@ int main(int argc, char **argv) { printf(" peak %d\n", m_get_peak_bytes_allocated()); */ - bool executed = false; + const int NOTHING_EXECUTED = -2; + int ret = NOTHING_EXECUTED; for (int a = 1; a < argc; a++) { if (argv[a][0] == '-') { if (strcmp(argv[a], "-c") == 0) { if (a + 1 >= argc) { return usage(argv); } - do_str(argv[a + 1]); - executed = true; + ret = do_str(argv[a + 1]); a += 1; } else if (strcmp(argv[a], "-X") == 0) { a += 1; } else if (strcmp(argv[a], "-v") == 0) { mp_verbose_flag++; + } else if (strcmp(argv[a], "-O") == 0) { + // optimisation; sets __debug__ to False + mp_set_debug(false); } else { return usage(argv); } @@ -344,7 +350,8 @@ int main(int argc, char **argv) { fprintf(stderr, "%s: can't open file '%s': [Errno %d] ", argv[0], argv[1], errno); perror(""); // CPython exits with 2 in such case - exit(2); + ret = 2; + break; } // Set base dir of the script as first entry in sys.path @@ -355,20 +362,20 @@ int main(int argc, char **argv) { for (int i = a; i < argc; i++) { mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i]))); } - do_file(argv[a]); - executed = true; + ret = do_file(argv[a]); break; } } - if (!executed) { + if (ret == NOTHING_EXECUTED) { do_repl(); + ret = 0; } mp_deinit(); //printf("total bytes = %d\n", m_get_total_bytes_allocated()); - return 0; + return ret; } STATIC mp_obj_t mp_sys_exit(uint n_args, const mp_obj_t *args) { diff --git a/unix/modffi.c b/unix/modffi.c index aa26297d60..4ac9fef5aa 100644 --- a/unix/modffi.c +++ b/unix/modffi.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/unix/modos.c b/unix/modos.c new file mode 100644 index 0000000000..d4951661da --- /dev/null +++ b/unix/modos.c @@ -0,0 +1,87 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include "misc.h" +#include "mpconfig.h" +#include "nlr.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include "objtuple.h" + +#define RAISE_ERRNO(err_flag, error_val) \ + { if (err_flag == -1) \ + { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)error_val))); } } + +STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) { + struct stat sb; + const char *path = mp_obj_str_get_str(path_in); + + int res = stat(path, &sb); + RAISE_ERRNO(res, errno); + + mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL); + t->items[0] = MP_OBJ_NEW_SMALL_INT((machine_int_t)sb.st_mode); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino); + t->items[2] = MP_OBJ_NEW_SMALL_INT((machine_int_t)sb.st_dev); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink); + t->items[4] = MP_OBJ_NEW_SMALL_INT((machine_int_t)sb.st_uid); + t->items[5] = MP_OBJ_NEW_SMALL_INT((machine_int_t)sb.st_gid); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size); + t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime); + t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime); + t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime); + return t; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_stat_obj, mod_os_stat); + +STATIC const mp_map_elem_t mp_module_os_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__os) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&mod_os_stat_obj }, +}; + +STATIC const mp_obj_dict_t mp_module_os_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = ARRAY_SIZE(mp_module_os_globals_table), + .alloc = ARRAY_SIZE(mp_module_os_globals_table), + .table = (mp_map_elem_t*)mp_module_os_globals_table, + }, +}; + +const mp_obj_module_t mp_module_os = { + .base = { &mp_type_module }, + .name = MP_QSTR__os, + .globals = (mp_obj_dict_t*)&mp_module_os_globals, +}; diff --git a/unix/modsocket.c b/unix/modsocket.c index 131d9285e4..5192c02438 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 4f347f4e02..6cac4f4cc7 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -45,17 +45,32 @@ #define MICROPY_MOD_SYS_EXIT (1) #define MICROPY_MOD_SYS_STDFILES (1) #define MICROPY_ENABLE_MOD_CMATH (1) +#define MICROPY_MOD_IO_FILEIO (1) // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. // names in exception messages (may require more RAM). #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +extern const struct _mp_obj_module_t mp_module_os; extern const struct _mp_obj_module_t mp_module_time; extern const struct _mp_obj_module_t mp_module_socket; extern const struct _mp_obj_module_t mp_module_ffi; + +#if MICROPY_MOD_FFI +#define MICROPY_MOD_FFI_DEF { MP_OBJ_NEW_QSTR(MP_QSTR_ffi), (mp_obj_t)&mp_module_ffi }, +#else +#define MICROPY_MOD_FFI_DEF +#endif +#if MICROPY_MOD_TIME +#define MICROPY_MOD_TIME_DEF { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_time }, +#else +#define MICROPY_MOD_TIME_DEF +#endif + #define MICROPY_EXTRA_BUILTIN_MODULES \ - { MP_OBJ_NEW_QSTR(MP_QSTR_ffi), (mp_obj_t)&mp_module_ffi }, \ - { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_time }, \ + MICROPY_MOD_FFI_DEF \ + MICROPY_MOD_TIME_DEF \ { MP_OBJ_NEW_QSTR(MP_QSTR_microsocket), (mp_obj_t)&mp_module_socket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR__os), (mp_obj_t)&mp_module_os }, \ // type definitions for the specific machine diff --git a/unix/qstrdefsport.h b/unix/qstrdefsport.h index 55a82ec067..de0b3d8fae 100644 --- a/unix/qstrdefsport.h +++ b/unix/qstrdefsport.h @@ -33,6 +33,9 @@ Q(makefile) Q(FileIO) +Q(_os) +Q(stat) + Q(ffi) Q(ffimod) Q(ffifunc) diff --git a/windows/Makefile b/windows/Makefile index 8fcc0b5815..a188979bd5 100644 --- a/windows/Makefile +++ b/windows/Makefile @@ -17,6 +17,9 @@ INC += -I$(BUILD) # compiler settings CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) LDFLAGS = $(LDFLAGS_MOD) -lm +ifeq ($(CROSS_COMPILE),i686-w64-mingw32-) +CFLAGS += -D__USE_MINGW_ANSI_STDIO=1 +endif # Debugging/Optimization ifdef DEBUG |