summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/compile.c2
-rw-r--r--py/misc.h2
-rw-r--r--py/objstr.c83
-rw-r--r--py/qstrdefs.h5
-rw-r--r--py/vm.c9
-rw-r--r--tests/basics/for_break.py12
-rw-r--r--tests/basics/for_return.py7
-rw-r--r--tests/basics/string_istest.py20
-rwxr-xr-xtests/run-tests15
9 files changed, 148 insertions, 7 deletions
diff --git a/py/compile.c b/py/compile.c
index c90772a7e3..1f0d90570e 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1745,7 +1745,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// And, if the loop never runs, the loop variable should never be assigned
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
START_BREAK_CONTINUE_BLOCK
- comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
+ // note that we don't need to pop anything when breaking from an optimise for loop
uint top_label = comp_next_label(comp);
uint entry_label = comp_next_label(comp);
diff --git a/py/misc.h b/py/misc.h
index 013b5f123e..fd54147efd 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -96,6 +96,8 @@ bool unichar_isalpha(unichar c);
bool unichar_isprint(unichar c);
bool unichar_isdigit(unichar c);
bool unichar_isxdigit(unichar c);
+bool unichar_isupper(unichar c);
+bool unichar_islower(unichar c);
unichar unichar_tolower(unichar c);
unichar unichar_toupper(unichar c);
diff --git a/py/objstr.c b/py/objstr.c
index d095c8b471..27f6d9cd6f 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -1502,6 +1502,79 @@ STATIC mp_obj_t str_upper(mp_obj_t self_in) {
return str_caseconv(CASE_UPPER, self_in);
}
+enum { IS_SPACE, IS_ALPHA, IS_DIGIT, IS_UPPER, IS_LOWER };
+
+STATIC mp_obj_t str_uni_istype(int type, mp_obj_t self_in) {
+ GET_STR_DATA_LEN(self_in, self_data, self_len);
+
+ if (self_len == 0) {
+ return mp_const_false; // default to False for empty str
+ }
+
+ typedef bool (*check_function)(unichar);
+ check_function f;
+
+ if (type != IS_UPPER && type != IS_LOWER) {
+ switch (type) {
+ case IS_SPACE: f = &unichar_isspace; break;
+ case IS_ALPHA: f = &unichar_isalpha; break;
+ case IS_DIGIT: f = &unichar_isdigit; break;
+ default:
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unknown type provided for str_uni_istype"));
+ }
+
+ for (int i = 0; i < self_len; i++) {
+ if (!f(*self_data++)) {
+ return mp_const_false;
+ }
+ }
+ } else {
+ switch (type) {
+ case IS_UPPER: f = &unichar_isupper; break;
+ case IS_LOWER: f = &unichar_islower; break;
+ default:
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unknown type provided for str_uni_istype"));
+ }
+
+ bool contains_alpha = false;
+
+ for (int i = 0; i < self_len; i++) { // only check alphanumeric characters
+ if (unichar_isalpha(*self_data++)) {
+ contains_alpha = true;
+ if (!f(*(self_data-1))) {
+ return mp_const_false; // we already incremented
+ }
+ }
+ }
+
+ if (!contains_alpha) {
+ return mp_const_false;
+ }
+ }
+
+ return mp_const_true;
+}
+
+STATIC mp_obj_t str_isspace(mp_obj_t self_in) {
+ return str_uni_istype(IS_SPACE, self_in);
+}
+
+STATIC mp_obj_t str_isalpha(mp_obj_t self_in) {
+ return str_uni_istype(IS_ALPHA, self_in);
+}
+
+STATIC mp_obj_t str_isdigit(mp_obj_t self_in) {
+ return str_uni_istype(IS_DIGIT, self_in);
+}
+
+STATIC mp_obj_t str_isupper(mp_obj_t self_in) {
+ return str_uni_istype(IS_UPPER, self_in);
+}
+
+STATIC mp_obj_t str_islower(mp_obj_t self_in) {
+ return str_uni_istype(IS_LOWER, self_in);
+}
+
#if MICROPY_CPYTHON_COMPAT
// These methods are superfluous in the presense of str() and bytes()
// constructors.
@@ -1569,6 +1642,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
STATIC const mp_map_elem_t str_locals_dict_table[] = {
#if MICROPY_CPYTHON_COMPAT
@@ -1594,6 +1672,11 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj },
};
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 2d4ddfea29..4ee56db909 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -246,6 +246,11 @@ Q(partition)
Q(rpartition)
Q(lower)
Q(upper)
+Q(isspace)
+Q(isalpha)
+Q(isdigit)
+Q(isupper)
+Q(islower)
Q(iterable)
Q(start)
diff --git a/py/vm.c b/py/vm.c
index c04eb89547..75093d2401 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -158,6 +158,13 @@ mp_vm_return_kind_t mp_execute_bytecode(const byte *code, const mp_obj_t *args,
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL);
#if DETECT_VM_STACK_OVERFLOW
+ if (vm_return_kind == MP_VM_RETURN_NORMAL) {
+ if (sp < state) {
+ printf("VM stack underflow: " INT_FMT "\n", sp - state);
+ assert(0);
+ }
+ }
+
// We can't check the case when an exception is returned in state[n_state - 1]
// and there are no arguments, because in this case our detection slot may have
// been overwritten by the returned exception (which is allowed).
@@ -171,7 +178,7 @@ mp_vm_return_kind_t mp_execute_bytecode(const byte *code, const mp_obj_t *args,
}
}
if (overflow) {
- printf("VM stack overflow state=%p n_state+1=%u\n", state, n_state);
+ printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", state, n_state);
assert(0);
}
}
diff --git a/tests/basics/for_break.py b/tests/basics/for_break.py
index fa8dabd150..f8bb0578e2 100644
--- a/tests/basics/for_break.py
+++ b/tests/basics/for_break.py
@@ -13,3 +13,15 @@ def foo():
i -= 1
foo()
+
+# break from within nested for loop
+def bar():
+ l = [1, 2, 3]
+ for e1 in l:
+ print(e1)
+ for e2 in l:
+ print(e1, e2)
+ if e2 == 2:
+ break
+
+bar()
diff --git a/tests/basics/for_return.py b/tests/basics/for_return.py
new file mode 100644
index 0000000000..0441352ad9
--- /dev/null
+++ b/tests/basics/for_return.py
@@ -0,0 +1,7 @@
+# test returning from within a for loop
+
+def f():
+ for i in [1, 2, 3]:
+ return i
+
+print(f())
diff --git a/tests/basics/string_istest.py b/tests/basics/string_istest.py
new file mode 100644
index 0000000000..7ea6c4508f
--- /dev/null
+++ b/tests/basics/string_istest.py
@@ -0,0 +1,20 @@
+print("".isspace())
+print(" \t\n\r\v\f".isspace())
+print("a".isspace())
+print(" \t\n\r\v\fa".isspace())
+print("".isalpha())
+print("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha())
+print("0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha())
+print("this ".isalpha())
+print("".isdigit())
+print("0123456789".isdigit())
+print("0123456789a".isdigit())
+print("0123456789 ".isdigit())
+print("".isupper())
+print("CHEESE-CAKE WITH ... _FROSTING_*99".isupper())
+print("aB".isupper())
+print("".islower())
+print("cheese-cake with ... _frosting_*99".islower())
+print("aB".islower())
+print("123".islower())
+print("123a".islower())
diff --git a/tests/run-tests b/tests/run-tests
index 102655abea..1e6dd50538 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -111,6 +111,7 @@ def run_tests(pyb, tests):
def main():
cmd_parser = argparse.ArgumentParser(description='Run tests for Micro Python.')
cmd_parser.add_argument('--pyboard', action='store_true', help='run the tests on the pyboard')
+ cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)')
cmd_parser.add_argument('files', nargs='*', help='input test files')
args = cmd_parser.parse_args()
@@ -122,12 +123,16 @@ def main():
pyb = None
if len(args.files) == 0:
- if pyb is None:
- # run PC tests
- test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc')
+ if args.test_dirs is None:
+ if pyb is None:
+ # run PC tests
+ test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc')
+ else:
+ # run pyboard tests
+ test_dirs = ('basics', 'float', 'pyb', 'pybnative', 'inlineasm')
else:
- # run pyboard tests
- test_dirs = ('basics', 'float', 'pyb', 'pybnative', 'inlineasm')
+ # run tests from these directories
+ test_dirs = args.test_dirs
tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files)
else:
# tests explicitly given