summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/builtin.c124
-rw-r--r--py/builtin.h39
-rw-r--r--py/builtineval.c50
-rw-r--r--py/builtinimport.c11
-rw-r--r--py/compile.c10
-rw-r--r--py/emitpass1.c5
-rw-r--r--py/gc.c7
-rw-r--r--py/grammar.h2
-rw-r--r--py/lexer.c28
-rw-r--r--py/lexer.h37
-rw-r--r--py/map.c67
-rw-r--r--py/map.h10
-rw-r--r--py/misc.h9
-rw-r--r--py/mpconfig.h17
-rw-r--r--py/mpqstrraw.h11
-rw-r--r--py/obj.c43
-rw-r--r--py/obj.h33
-rw-r--r--py/objbool.c2
-rw-r--r--py/objcomplex.c2
-rw-r--r--py/objdict.c26
-rw-r--r--py/objenumerate.c53
-rw-r--r--py/objexcept.c123
-rw-r--r--py/objfilter.c58
-rw-r--r--py/objfloat.c2
-rw-r--r--py/objfun.c80
-rw-r--r--py/objgenerator.c2
-rw-r--r--py/objint.c56
-rw-r--r--py/objint.h9
-rw-r--r--py/objlist.c73
-rw-r--r--py/objmap.c60
-rw-r--r--py/objmodule.c2
-rw-r--r--py/objnone.c2
-rw-r--r--py/objset.c401
-rw-r--r--py/objslice.c4
-rw-r--r--py/objstr.c71
-rw-r--r--py/objtuple.c31
-rw-r--r--py/objtuple.h7
-rw-r--r--py/objtype.c4
-rw-r--r--py/objzip.c57
-rw-r--r--py/parse.c72
-rw-r--r--py/parse.h3
-rw-r--r--py/py.mk5
-rw-r--r--py/runtime.c126
-rw-r--r--py/runtime.h6
-rw-r--r--py/stream.c86
-rw-r--r--py/stream.h2
-rw-r--r--py/strtonum.c2
-rw-r--r--py/strtonum.h1
-rw-r--r--py/vm.c15
-rw-r--r--py/vstr.c45
50 files changed, 1602 insertions, 389 deletions
diff --git a/py/builtin.c b/py/builtin.c
index 078f4b49c3..04bb2681db 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -18,7 +18,7 @@
// args[0] is function from class body
// args[1] is class name
// args[2:] are base objects
-mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
+static mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
assert(2 <= n_args);
// we differ from CPython: we set the new __locals__ object here
@@ -62,14 +62,16 @@ mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__);
-mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
+static mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
if (o != mp_const_none) {
- mp_obj_print(o);
+ mp_obj_print(o, PRINT_REPR);
printf("\n");
}
return mp_const_none;
}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
+
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
if (MP_OBJ_IS_SMALL_INT(o_in)) {
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
@@ -97,7 +99,9 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
}
}
-mp_obj_t mp_builtin_all(mp_obj_t o_in) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs);
+
+static mp_obj_t mp_builtin_all(mp_obj_t o_in) {
mp_obj_t iterable = rt_getiter(o_in);
mp_obj_t item;
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
@@ -108,7 +112,9 @@ mp_obj_t mp_builtin_all(mp_obj_t o_in) {
return mp_const_true;
}
-mp_obj_t mp_builtin_any(mp_obj_t o_in) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all);
+
+static mp_obj_t mp_builtin_any(mp_obj_t o_in) {
mp_obj_t iterable = rt_getiter(o_in);
mp_obj_t item;
while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
@@ -119,7 +125,9 @@ mp_obj_t mp_builtin_any(mp_obj_t o_in) {
return mp_const_false;
}
-mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
+
+static mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
if (mp_obj_is_callable(o_in)) {
return mp_const_true;
} else {
@@ -127,19 +135,21 @@ mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
}
}
-mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);
+
+static mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
int ord = mp_obj_get_int(o_in);
if (0 <= ord && ord <= 0x10ffff) {
- char *str = m_new(char, 2);
- str[0] = ord;
- str[1] = '\0';
- return mp_obj_new_str(qstr_from_str_take(str, 2));
+ char str[2] = {ord, '\0'};
+ return mp_obj_new_str(qstr_from_strn_copy(str, 1));
} else {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "chr() arg not in range(0x110000)"));
}
}
-mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);
+
+static mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
@@ -152,6 +162,8 @@ mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
}
}
+MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod);
+
static mp_obj_t mp_builtin_hash(mp_obj_t o_in) {
// TODO hash will generally overflow small integer; can we safely truncate it?
return mp_obj_new_int(mp_obj_hash(o_in));
@@ -165,7 +177,7 @@ static mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
-mp_obj_t mp_builtin_len(mp_obj_t o_in) {
+static mp_obj_t mp_builtin_len(mp_obj_t o_in) {
mp_obj_t len = mp_obj_len_maybe(o_in);
if (len == NULL) {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
@@ -174,7 +186,9 @@ mp_obj_t mp_builtin_len(mp_obj_t o_in) {
}
}
-mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_builtin_len);
+
+static mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {
if (n_args == 1) {
// given an iterable
mp_obj_t iterable = rt_getiter(args[0]);
@@ -201,7 +215,9 @@ mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {
}
}
-mp_obj_t mp_builtin_min(int n_args, const mp_obj_t *args) {
+MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_max_obj, 1, mp_builtin_max);
+
+static mp_obj_t mp_builtin_min(int n_args, const mp_obj_t *args) {
if (n_args == 1) {
// given an iterable
mp_obj_t iterable = rt_getiter(args[0]);
@@ -228,6 +244,8 @@ mp_obj_t mp_builtin_min(int n_args, const mp_obj_t *args) {
}
}
+MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
+
static mp_obj_t mp_builtin_next(mp_obj_t o) {
mp_obj_t ret = rt_iternext(o);
if (ret == mp_const_stop_iteration) {
@@ -239,7 +257,7 @@ static mp_obj_t mp_builtin_next(mp_obj_t o) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next);
-mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
+static mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
const char *str = qstr_str(mp_obj_get_qstr(o_in));
if (strlen(str) == 1) {
return mp_obj_new_int(str[0]);
@@ -248,46 +266,56 @@ mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
}
}
-mp_obj_t mp_builtin_pow(int n_args, const mp_obj_t *args) {
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);
+
+static mp_obj_t mp_builtin_pow(int n_args, const mp_obj_t *args) {
+ assert(2 <= n_args && n_args <= 3);
switch (n_args) {
case 2: return rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]);
- case 3: return rt_binary_op(RT_BINARY_OP_MODULO, rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise...
- default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "pow expected at most 3 arguments, got %d", n_args));
+ default: return rt_binary_op(RT_BINARY_OP_MODULO, rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise...
}
}
-mp_obj_t mp_builtin_print(int n_args, const mp_obj_t *args) {
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);
+
+static mp_obj_t mp_builtin_print(int n_args, const mp_obj_t *args) {
for (int i = 0; i < n_args; i++) {
if (i > 0) {
printf(" ");
}
- if (MP_OBJ_IS_TYPE(args[i], &str_type)) {
- // special case, print string raw
- printf("%s", qstr_str(mp_obj_str_get(args[i])));
- } else {
- // print the object Python style
- mp_obj_print(args[i]);
- }
+ mp_obj_print(args[i], PRINT_STR);
}
printf("\n");
return mp_const_none;
}
-mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args) {
+MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_print_obj, 0, mp_builtin_print);
+
+static mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args) {
+ assert(1 <= n_args && n_args <= 3);
switch (n_args) {
case 1: return mp_obj_new_range(0, mp_obj_get_int(args[0]), 1);
case 2: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), 1);
- case 3: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
- default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "range expected at most 3 arguments, got %d", n_args));
+ default: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
}
}
-mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_range_obj, 1, 3, mp_builtin_range);
+
+static mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
+ vstr_t *vstr = vstr_new();
+ mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR);
+ return mp_obj_new_str(qstr_from_str_take(vstr->buf, vstr->alloc));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);
+
+static mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
+ assert(1 <= n_args && n_args <= 2);
mp_obj_t value;
switch (n_args) {
case 1: value = mp_obj_new_int(0); break;
- case 2: value = args[1]; break;
- default: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "sum expected at most 2 arguments, got %d", n_args));
+ default: value = args[1]; break;
}
mp_obj_t iterable = rt_getiter(args[0]);
mp_obj_t item;
@@ -296,3 +324,33 @@ mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
}
return value;
}
+
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);
+
+static mp_obj_t mp_builtin_sorted(mp_obj_t args, mp_map_t *kwargs) {
+ mp_obj_t *args_items = NULL;
+ uint args_len = 0;
+
+ assert(MP_OBJ_IS_TYPE(args, &tuple_type));
+ mp_obj_tuple_get(args, &args_len, &args_items);
+ assert(args_len >= 1);
+ if (args_len > 1) {
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
+ "must use keyword argument for key function"));
+ }
+ mp_obj_t self = list_type.make_new((mp_obj_t)&list_type, 1, args_items);
+ mp_obj_t new_args = rt_build_tuple(1, &self);
+ mp_obj_list_sort(new_args, kwargs);
+
+ return self;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
+
+static mp_obj_t mp_builtin_str(mp_obj_t o_in) {
+ vstr_t *vstr = vstr_new();
+ mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, o_in, PRINT_STR);
+ return mp_obj_new_str(qstr_from_str_take(vstr->buf, vstr->alloc));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_str_obj, mp_builtin_str);
diff --git a/py/builtin.h b/py/builtin.h
index db7d517a06..f4038b47b4 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -1,25 +1,28 @@
-// TODO convert all these to objects using MP_DECLARE and MP_DEFINE
+mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
-mp_obj_t mp_builtin___import__(int n, mp_obj_t *args);
-mp_obj_t mp_builtin___repl_print__(mp_obj_t o);
-mp_obj_t mp_builtin_abs(mp_obj_t o_in);
-mp_obj_t mp_builtin_all(mp_obj_t o_in);
-mp_obj_t mp_builtin_any(mp_obj_t o_in);
-mp_obj_t mp_builtin_callable(mp_obj_t o_in);
-mp_obj_t mp_builtin_chr(mp_obj_t o_in);
-mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_eval_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hash_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_isinstance_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_issubclass_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_iter_obj);
-mp_obj_t mp_builtin_len(mp_obj_t o_in);
-mp_obj_t mp_builtin_list(int n_args, const mp_obj_t *args);
-mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args);
-mp_obj_t mp_builtin_min(int n_args, const mp_obj_t *args);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_len_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_list_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_max_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_min_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_next_obj);
-mp_obj_t mp_builtin_ord(mp_obj_t o_in);
-mp_obj_t mp_builtin_pow(int n_args, const mp_obj_t *args);
-mp_obj_t mp_builtin_print(int n_args, const mp_obj_t *args);
-mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args);
-mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_ord_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_pow_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_print_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_range_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_str_obj);
diff --git a/py/builtineval.c b/py/builtineval.c
new file mode 100644
index 0000000000..a8a7a476a3
--- /dev/null
+++ b/py/builtineval.c
@@ -0,0 +1,50 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "lexer.h"
+#include "lexerunix.h"
+#include "parse.h"
+#include "obj.h"
+#include "compile.h"
+#include "runtime0.h"
+#include "runtime.h"
+#include "map.h"
+#include "builtin.h"
+
+static mp_obj_t mp_builtin_eval(mp_obj_t o_in) {
+ const char *str = qstr_str(mp_obj_get_qstr(o_in));
+
+ // create the lexer
+ mp_lexer_t *lex = mp_lexer_new_from_str_len("<string>", str, strlen(str), 0);
+
+ // parse the string
+ qstr parse_exc_id;
+ const char *parse_exc_msg;
+ mp_parse_node_t pn = mp_parse(lex, MP_PARSE_EVAL_INPUT, &parse_exc_id, &parse_exc_msg);
+ mp_lexer_free(lex);
+
+ if (pn == MP_PARSE_NODE_NULL) {
+ // parse error; raise exception
+ nlr_jump(mp_obj_new_exception_msg(parse_exc_id, parse_exc_msg));
+ }
+
+ // compile the string
+ mp_obj_t module_fun = mp_compile(pn, false);
+
+ if (module_fun == mp_const_none) {
+ // TODO handle compile error correctly
+ return mp_const_none;
+ }
+
+ // complied successfully, execute it
+ return rt_call_function_0(module_fun);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_eval_obj, mp_builtin_eval);
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 90a0fc3394..2eca36fbc6 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -18,7 +18,7 @@
#include "map.h"
#include "builtin.h"
-mp_obj_t mp_builtin___import__(int n, mp_obj_t *args) {
+mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
/*
printf("import:\n");
for (int i = 0; i < n; i++) {
@@ -48,16 +48,19 @@ mp_obj_t mp_builtin___import__(int n, mp_obj_t *args) {
rt_globals_set(mp_obj_module_get_globals(module_obj));
// parse the imported script
- mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT);
+ qstr parse_exc_id;
+ const char *parse_exc_msg;
+ mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_exc_id, &parse_exc_msg);
mp_lexer_free(lex);
if (pn == MP_PARSE_NODE_NULL) {
- // TODO handle parse error correctly
+ // parse error; clean up and raise exception
rt_locals_set(old_locals);
rt_globals_set(old_globals);
- return mp_const_none;
+ nlr_jump(mp_obj_new_exception_msg(parse_exc_id, parse_exc_msg));
}
+ // compile the imported script
mp_obj_t module_fun = mp_compile(pn, false);
if (module_fun == mp_const_none) {
diff --git a/py/compile.c b/py/compile.c
index 2e22d64262..b24e94a8dc 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1316,7 +1316,7 @@ void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
int l_end = comp_next_label(comp);
c_if_cond(comp, pns->nodes[0], true, l_end);
- EMIT(load_id, MP_QSTR_AssertionError);
+ EMIT(load_global, MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
// assertion message
compile_node(comp, pns->nodes[1]);
@@ -2708,7 +2708,12 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
#endif
// compile
- if (scope->kind == SCOPE_MODULE) {
+ if (MP_PARSE_NODE_IS_STRUCT_KIND(scope->pn, PN_eval_input)) {
+ assert(scope->kind == SCOPE_MODULE);
+ mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn;
+ compile_node(comp, pns->nodes[0]); // compile the expression
+ EMIT(return_value);
+ } else if (scope->kind == SCOPE_MODULE) {
if (!comp->is_repl) {
check_for_doc_string(comp, scope->pn);
}
@@ -2833,7 +2838,6 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
}
EMIT(end_pass);
-
}
void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
diff --git a/py/emitpass1.c b/py/emitpass1.c
index 2f0ecac86d..60fdd0b825 100644
--- a/py/emitpass1.c
+++ b/py/emitpass1.c
@@ -45,10 +45,7 @@ static void emit_pass1_load_id(emit_t *emit, qstr qstr) {
bool added;
id_info_t *id = scope_find_or_add_id(emit->scope, qstr, &added);
if (added) {
- if (qstr == MP_QSTR_AssertionError) {
- // TODO how much of a hack is this?
- id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
- } else if (strcmp(qstr_str(qstr), "super") == 0 && emit->scope->kind == SCOPE_FUNCTION) {
+ if (strcmp(qstr_str(qstr), "super") == 0 && emit->scope->kind == SCOPE_FUNCTION) {
// special case, super is a global, and also counts as use of __class__
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
id_info_t *id2 = scope_find_local_in_parent(emit->scope, emit->qstr___class__);
diff --git a/py/gc.c b/py/gc.c
index 054a3cc315..70b071ebc8 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -8,15 +8,8 @@
#if MICROPY_ENABLE_GC
-// a machine word is big enough to hold a pointer
-/*
-#define BYTES_PER_WORD (8)
-typedef unsigned long machine_uint_t;
-*/
typedef unsigned char byte;
-#define BITS_PER_BYTE (8)
-#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
#define WORDS_PER_BLOCK (4)
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
#define STACK_SIZE (64) // tunable; minimum is 1
diff --git a/py/grammar.h b/py/grammar.h
index 4d53bd3fc4..32be6c66ca 100644
--- a/py/grammar.h
+++ b/py/grammar.h
@@ -15,6 +15,8 @@ DEF_RULE(single_input, nc, or(3), tok(NEWLINE), rule(simple_stmt), rule(compound
DEF_RULE(file_input, nc, and(1), opt_rule(file_input_2))
DEF_RULE(file_input_2, c(generic_all_nodes), one_or_more, rule(file_input_3))
DEF_RULE(file_input_3, nc, or(2), tok(NEWLINE), rule(stmt))
+DEF_RULE(eval_input, nc, and(2), rule(testlist), opt_rule(eval_input_2))
+DEF_RULE(eval_input_2, nc, and(1), tok(NEWLINE))
// decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
// decorators: decorator+
diff --git a/py/lexer.c b/py/lexer.c
index d4205236c3..6feb231e0c 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -35,6 +35,7 @@ struct _mp_lexer_t {
mp_token_t tok_cur;
};
+// TODO replace with a call to a standard function
bool str_strn_equal(const char *str, const char *strn, int len) {
uint i = 0;
@@ -66,15 +67,6 @@ void mp_token_show(const mp_token_t *tok) {
printf("\n");
}
-void mp_token_show_error_prefix(const mp_token_t *tok) {
- printf("(%s:%d:%d) ", tok->src_name, tok->src_line, tok->src_column);
-}
-
-bool mp_token_show_error(const mp_token_t *tok, const char *msg) {
- printf("(%s:%d:%d) %s\n", tok->src_name, tok->src_line, tok->src_column, msg);
- return false;
-}
-
#define CUR_CHAR(lex) ((lex)->chr0)
static bool is_end(mp_lexer_t *lex) {
@@ -299,8 +291,15 @@ static void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
// backslash (outside string literals) must appear just before a physical newline
next_char(lex);
if (!is_physical_newline(lex)) {
- // TODO SyntaxError
- assert(0);
+ // SyntaxError: unexpected character after line continuation character
+ tok->src_name = lex->name;
+ tok->src_line = lex->line;
+ tok->src_column = lex->column;
+ tok->kind = MP_TOKEN_BAD_LINE_CONTINUATION;
+ vstr_reset(&lex->vstr);
+ tok->str = vstr_str(&lex->vstr);
+ tok->len = 0;
+ return;
} else {
next_char(lex);
}
@@ -607,7 +606,7 @@ mp_lexer_t *mp_lexer_new(const char *src_name, void *stream_data, mp_lexer_strea
lex->num_indent_level = 1;
lex->indent_level = m_new(uint16_t, lex->alloc_indent_level);
lex->indent_level[0] = 0;
- vstr_init(&lex->vstr);
+ vstr_init(&lex->vstr, 32);
// preload characters
lex->chr0 = stream_next_char(stream_data);
@@ -677,8 +676,9 @@ bool mp_lexer_opt_str(mp_lexer_t *lex, const char *str) {
}
*/
-bool mp_lexer_show_error(mp_lexer_t *lex, const char *msg) {
- return mp_token_show_error(&lex->tok_cur, msg);
+bool mp_lexer_show_error_pythonic_prefix(mp_lexer_t *lex) {
+ printf(" File \"%s\", line %d column %d\n", lex->tok_cur.src_name, lex->tok_cur.src_line, lex->tok_cur.src_column);
+ return false;
}
bool mp_lexer_show_error_pythonic(mp_lexer_t *lex, const char *msg) {
diff --git a/py/lexer.h b/py/lexer.h
index 9dfcb128c5..ea928c77f8 100644
--- a/py/lexer.h
+++ b/py/lexer.h
@@ -10,19 +10,20 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_INVALID,
MP_TOKEN_DEDENT_MISMATCH,
MP_TOKEN_LONELY_STRING_OPEN,
+ MP_TOKEN_BAD_LINE_CONTINUATION,
- MP_TOKEN_NEWLINE, // 4
- MP_TOKEN_INDENT, // 5
- MP_TOKEN_DEDENT, // 6
+ MP_TOKEN_NEWLINE, // 5
+ MP_TOKEN_INDENT, // 6
+ MP_TOKEN_DEDENT, // 7
- MP_TOKEN_NAME, // 7
+ MP_TOKEN_NAME, // 8
MP_TOKEN_NUMBER,
MP_TOKEN_STRING,
MP_TOKEN_BYTES,
MP_TOKEN_ELLIPSIS,
- MP_TOKEN_KW_FALSE, // 12
+ MP_TOKEN_KW_FALSE, // 13
MP_TOKEN_KW_NONE,
MP_TOKEN_KW_TRUE,
MP_TOKEN_KW_AND,
@@ -31,7 +32,7 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_KW_BREAK,
MP_TOKEN_KW_CLASS,
MP_TOKEN_KW_CONTINUE,
- MP_TOKEN_KW_DEF, // 21
+ MP_TOKEN_KW_DEF, // 22
MP_TOKEN_KW_DEL,
MP_TOKEN_KW_ELIF,
MP_TOKEN_KW_ELSE,
@@ -41,7 +42,7 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_KW_FROM,
MP_TOKEN_KW_GLOBAL,
MP_TOKEN_KW_IF,
- MP_TOKEN_KW_IMPORT, // 31
+ MP_TOKEN_KW_IMPORT, // 32
MP_TOKEN_KW_IN,
MP_TOKEN_KW_IS,
MP_TOKEN_KW_LAMBDA,
@@ -51,12 +52,12 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_KW_PASS,
MP_TOKEN_KW_RAISE,
MP_TOKEN_KW_RETURN,
- MP_TOKEN_KW_TRY, // 41
+ MP_TOKEN_KW_TRY, // 42
MP_TOKEN_KW_WHILE,
MP_TOKEN_KW_WITH,
MP_TOKEN_KW_YIELD,
- MP_TOKEN_OP_PLUS, // 45
+ MP_TOKEN_OP_PLUS, // 46
MP_TOKEN_OP_MINUS,
MP_TOKEN_OP_STAR,
MP_TOKEN_OP_DBL_STAR,
@@ -66,7 +67,7 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_OP_LESS,
MP_TOKEN_OP_DBL_LESS,
MP_TOKEN_OP_MORE,
- MP_TOKEN_OP_DBL_MORE, // 55
+ MP_TOKEN_OP_DBL_MORE, // 56
MP_TOKEN_OP_AMPERSAND,
MP_TOKEN_OP_PIPE,
MP_TOKEN_OP_CARET,
@@ -76,7 +77,7 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_OP_DBL_EQUAL,
MP_TOKEN_OP_NOT_EQUAL,
- MP_TOKEN_DEL_PAREN_OPEN, // 64
+ MP_TOKEN_DEL_PAREN_OPEN, // 65
MP_TOKEN_DEL_PAREN_CLOSE,
MP_TOKEN_DEL_BRACKET_OPEN,
MP_TOKEN_DEL_BRACKET_CLOSE,
@@ -86,7 +87,7 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_DEL_COLON,
MP_TOKEN_DEL_PERIOD,
MP_TOKEN_DEL_SEMICOLON,
- MP_TOKEN_DEL_AT, // 74
+ MP_TOKEN_DEL_AT, // 75
MP_TOKEN_DEL_EQUAL,
MP_TOKEN_DEL_PLUS_EQUAL,
MP_TOKEN_DEL_MINUS_EQUAL,
@@ -96,7 +97,7 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_DEL_PERCENT_EQUAL,
MP_TOKEN_DEL_AMPERSAND_EQUAL,
MP_TOKEN_DEL_PIPE_EQUAL,
- MP_TOKEN_DEL_CARET_EQUAL, // 84
+ MP_TOKEN_DEL_CARET_EQUAL, // 85
MP_TOKEN_DEL_DBL_MORE_EQUAL,
MP_TOKEN_DEL_DBL_LESS_EQUAL,
MP_TOKEN_DEL_DBL_STAR_EQUAL,
@@ -123,8 +124,6 @@ typedef void (*mp_lexer_stream_close_t)(void*);
typedef struct _mp_lexer_t mp_lexer_t;
void mp_token_show(const mp_token_t *tok);
-void mp_token_show_error_prefix(const mp_token_t *tok);
-bool mp_token_show_error(const mp_token_t *tok, const char *msg);
mp_lexer_t *mp_lexer_new(const char *src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close);
mp_lexer_t *mp_lexer_new_from_str_len(const char *src_name, const char *str, uint len, uint free_len);
@@ -133,12 +132,8 @@ void mp_lexer_free(mp_lexer_t *lex);
void mp_lexer_to_next(mp_lexer_t *lex);
const mp_token_t *mp_lexer_cur(const mp_lexer_t *lex);
bool mp_lexer_is_kind(mp_lexer_t *lex, mp_token_kind_t kind);
-/* unused
-bool mp_lexer_is_str(mp_lexer_t *lex, const char *str);
-bool mp_lexer_opt_kind(mp_lexer_t *lex, mp_token_kind_t kind);
-bool mp_lexer_opt_str(mp_lexer_t *lex, const char *str);
-*/
-bool mp_lexer_show_error(mp_lexer_t *lex, const char *msg);
+
+bool mp_lexer_show_error_pythonic_prefix(mp_lexer_t *lex);
bool mp_lexer_show_error_pythonic(mp_lexer_t *lex, const char *msg);
// used to import a module; must be implemented for a specific port
diff --git a/py/map.c b/py/map.c
index e44cf33d26..1ce763ab0e 100644
--- a/py/map.c
+++ b/py/map.c
@@ -132,28 +132,45 @@ void mp_set_init(mp_set_t *set, int n) {
set->table = m_new0(mp_obj_t, set->alloc);
}
-mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found) {
- int hash = mp_obj_hash(index);
- assert(set->alloc); /* FIXME: if alloc is ever 0 when doing a lookup, this'll fail: */
- int pos = hash % set->alloc;
+static void mp_set_rehash(mp_set_t *set) {
+ int old_alloc = set->alloc;
+ mp_obj_t *old_table = set->table;
+ set->alloc = get_doubling_prime_greater_or_equal_to(set->alloc + 1);
+ set->used = 0;
+ set->table = m_new0(mp_obj_t, set->alloc);
+ for (int i = 0; i < old_alloc; i++) {
+ if (old_table[i] != NULL) {
+ mp_set_lookup(set, old_table[i], true);
+ }
+ }
+ m_del(mp_obj_t, old_table, old_alloc);
+}
+
+mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
+ int hash;
+ int pos;
+ if (set->alloc == 0) {
+ if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
+ mp_set_rehash(set);
+ } else {
+ return NULL;
+ }
+ }
+ if (lookup_kind & MP_MAP_LOOKUP_FIRST) {
+ hash = 0;
+ pos = 0;
+ } else {
+ hash = mp_obj_hash(index);;
+ pos = hash % set->alloc;
+ }
for (;;) {
mp_obj_t elem = set->table[pos];
if (elem == MP_OBJ_NULL) {
// not in table
- if (add_if_not_found) {
+ if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
if (set->used + 1 >= set->alloc) {
// not enough room in table, rehash it
- int old_alloc = set->alloc;
- mp_obj_t *old_table = set->table;
- set->alloc = get_doubling_prime_greater_or_equal_to(set->alloc + 1);
- set->used = 0;
- set->table = m_new(mp_obj_t, set->alloc);
- for (int i = 0; i < old_alloc; i++) {
- if (old_table[i] != NULL) {
- mp_set_lookup(set, old_table[i], true);
- }
- }
- m_del(mp_obj_t, old_table, old_alloc);
+ mp_set_rehash(set);
// restart the search for the new element
pos = hash % set->alloc;
} else {
@@ -161,11 +178,17 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found) {
set->table[pos] = index;
return index;
}
+ } else if (lookup_kind & MP_MAP_LOOKUP_FIRST) {
+ pos++;
} else {
return MP_OBJ_NULL;
}
- } else if (mp_obj_equal(elem, index)) {
+ } else if (lookup_kind & MP_MAP_LOOKUP_FIRST || mp_obj_equal(elem, index)) {
// found it
+ if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
+ set->used--;
+ set->table[pos] = NULL;
+ }
return elem;
} else {
// not yet found, keep searching in this table
@@ -173,3 +196,13 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found) {
}
}
}
+
+void mp_set_clear(mp_set_t *set) {
+ set->used = 0;
+ machine_uint_t a = set->alloc;
+ set->alloc = 0;
+ set->table = m_renew(mp_obj_t, set->table, a, set->alloc);
+ for (uint i=0; i<set->alloc; i++) {
+ set->table[i] = NULL;
+ }
+}
diff --git a/py/map.h b/py/map.h
index 5ce4e835b6..2db0ac3ebc 100644
--- a/py/map.h
+++ b/py/map.h
@@ -19,9 +19,10 @@ typedef struct _mp_set_t {
} mp_set_t;
typedef enum _mp_map_lookup_kind_t {
- MP_MAP_LOOKUP,
- MP_MAP_LOOKUP_ADD_IF_NOT_FOUND,
- MP_MAP_LOOKUP_REMOVE_IF_FOUND,
+ MP_MAP_LOOKUP, // 0
+ MP_MAP_LOOKUP_ADD_IF_NOT_FOUND, // 1
+ MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2
+ MP_MAP_LOOKUP_FIRST = 4,
} mp_map_lookup_kind_t;
int get_doubling_prime_greater_or_equal_to(int x);
@@ -31,4 +32,5 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
void mp_map_clear(mp_map_t *map);
void mp_set_init(mp_set_t *set, int n);
-mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, bool add_if_not_found);
+mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
+void mp_set_clear(mp_set_t *set);
diff --git a/py/misc.h b/py/misc.h
index 1bf4d8f291..5b012d03dc 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -21,6 +21,7 @@ typedef unsigned int uint;
#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
#define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))
#define m_del_obj(type, ptr) (m_del(type, ptr, 1))
+#define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
void *m_malloc(int num_bytes);
void *m_malloc0(int num_bytes);
@@ -49,6 +50,8 @@ bool unichar_isdigit(unichar c);
#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
*/
+long strtonum(const char *restrict s, int base);
+
/** variable string *********************************************/
typedef struct _vstr_t {
@@ -58,15 +61,19 @@ typedef struct _vstr_t {
bool had_error;
} vstr_t;
-void vstr_init(vstr_t *vstr);
+void vstr_init(vstr_t *vstr, int alloc);
void vstr_clear(vstr_t *vstr);
vstr_t *vstr_new(void);
+vstr_t *vstr_new_size(int alloc);
void vstr_free(vstr_t *vstr);
void vstr_reset(vstr_t *vstr);
bool vstr_had_error(vstr_t *vstr);
char *vstr_str(vstr_t *vstr);
int vstr_len(vstr_t *vstr);
void vstr_hint_size(vstr_t *vstr, int size);
+char *vstr_extend(vstr_t *vstr, int size);
+bool vstr_set_size(vstr_t *vstr, int size);
+bool vstr_shrink(vstr_t *vstr);
char *vstr_add_len(vstr_t *vstr, int len);
void vstr_add_byte(vstr_t *vstr, byte v);
void vstr_add_char(vstr_t *vstr, unichar chr);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 2017ba366a..5d8c57692e 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -62,6 +62,18 @@
#define MICROPY_ENABLE_LEXER_UNIX (0)
#endif
+// Long int implementation
+#define MICROPY_LONGINT_IMPL_NONE (0)
+#define MICROPY_LONGINT_IMPL_LONGLONG (1)
+
+#ifndef MICROPY_LONGINT_IMPL
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
+#endif
+
+#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+typedef long long mp_longint_impl_t;
+#endif
+
// Whether to support float and complex types
#ifndef MICROPY_ENABLE_FLOAT
#define MICROPY_ENABLE_FLOAT (0)
@@ -76,6 +88,11 @@
/*****************************************************************************/
/* Miscellaneous settings */
+#define BITS_PER_BYTE (8)
+#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
+// machine_int_t value with most significant bit set
+#define WORD_MSBIT_HIGH (((machine_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
+
// printf format spec to use for machine_int_t and friends
#ifndef INT_FMT
#ifdef __LP64__
diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h
index e4404a36f0..6674a2c398 100644
--- a/py/mpqstrraw.h
+++ b/py/mpqstrraw.h
@@ -24,13 +24,14 @@ Q(StopIteration)
Q(AssertionError)
Q(AttributeError)
+Q(IndentationError)
Q(IndexError)
Q(KeyError)
Q(NameError)
+Q(OSError)
Q(SyntaxError)
Q(TypeError)
Q(ValueError)
-Q(OSError)
Q(abs)
Q(all)
@@ -41,6 +42,9 @@ Q(chr)
Q(complex)
Q(dict)
Q(divmod)
+Q(enumerate)
+Q(eval)
+Q(filter)
Q(float)
Q(hash)
Q(int)
@@ -49,6 +53,7 @@ Q(issubclass)
Q(iter)
Q(len)
Q(list)
+Q(map)
Q(max)
Q(min)
Q(next)
@@ -56,10 +61,14 @@ Q(ord)
Q(pow)
Q(print)
Q(range)
+Q(repr)
Q(set)
+Q(sorted)
Q(sum)
+Q(str)
Q(tuple)
Q(type)
+Q(zip)
Q(append)
Q(pop)
diff --git a/py/obj.c b/py/obj.c
index 866b9aaefa..9ca3d5d16b 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -13,7 +13,6 @@
#include "runtime0.h"
#include "runtime.h"
#include "map.h"
-#include "strtonum.h"
mp_obj_t mp_obj_get_type(mp_obj_t o_in) {
if (MP_OBJ_IS_SMALL_INT(o_in)) {
@@ -42,21 +41,21 @@ void printf_wrapper(void *env, const char *fmt, ...) {
va_end(args);
}
-void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
if (MP_OBJ_IS_SMALL_INT(o_in)) {
print(env, "%d", (int)MP_OBJ_SMALL_INT_VALUE(o_in));
} else {
mp_obj_base_t *o = o_in;
if (o->type->print != NULL) {
- o->type->print(print, env, o_in);
+ o->type->print(print, env, o_in, kind);
} else {
print(env, "<%s>", o->type->name);
}
}
}
-void mp_obj_print(mp_obj_t o_in) {
- mp_obj_print_helper(printf_wrapper, NULL, o_in);
+void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_obj_print_helper(printf_wrapper, NULL, o_in, kind);
}
bool mp_obj_is_callable(mp_obj_t o_in) {
@@ -109,15 +108,28 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
return val == 0;
} else if (o2 == mp_const_true) {
return val == 1;
- } else {
- return false;
+ } else if (MP_OBJ_IS_TYPE(o2, &int_type)) {
+ // If o2 is long int, dispatch to its virtual methods
+ mp_obj_base_t *o = o2;
+ if (o->type->binary_op != NULL) {
+ mp_obj_t r = o->type->binary_op(RT_COMPARE_OP_EQUAL, o2, o1);
+ return r == mp_const_true ? true : false;
+ }
}
+ return false;
}
} else if (MP_OBJ_IS_QSTR(o1) || MP_OBJ_IS_QSTR(o2)) {
return false;
} else if (MP_OBJ_IS_TYPE(o1, &str_type) && MP_OBJ_IS_TYPE(o2, &str_type)) {
return mp_obj_str_get(o1) == mp_obj_str_get(o2);
} else {
+ mp_obj_base_t *o = o1;
+ if (o->type->binary_op != NULL) {
+ mp_obj_t r = o->type->binary_op(RT_COMPARE_OP_EQUAL, o1, o2);
+ if (r != MP_OBJ_NULL) {
+ return r == mp_const_true ? true : false;
+ }
+ }
// TODO: Debugging helper
printf("Equality for '%s' and '%s' types not yet implemented\n", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2));
assert(0);
@@ -137,12 +149,6 @@ bool mp_obj_less(mp_obj_t o1, mp_obj_t o2) {
}
machine_int_t mp_obj_get_int(mp_obj_t arg) {
- return mp_obj_get_int_base(arg, 0);
-}
-
-machine_int_t mp_obj_get_int_base(mp_obj_t arg, mp_obj_t base_arg) {
- const char *value;
- int base;
if (arg == mp_const_false) {
return 0;
} else if (arg == mp_const_true) {
@@ -154,17 +160,6 @@ machine_int_t mp_obj_get_int_base(mp_obj_t arg, mp_obj_t base_arg) {
// TODO work out if this should be floor, ceil or trunc
return (machine_int_t)mp_obj_float_get(arg);
#endif
- } else if (MP_OBJ_IS_TYPE(arg, &str_type)) {
- if (base_arg == 0) {
- value = qstr_str(mp_obj_str_get(arg));
- return (machine_int_t)strtonum(value, 0);
- } else if (MP_OBJ_IS_SMALL_INT(base_arg)) {
- base = MP_OBJ_SMALL_INT_VALUE(base_arg);
- value = qstr_str(mp_obj_str_get(arg));
- return (machine_int_t)strtonum(value, base);
- } else {
- nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "an integer is required"));
- }
} else {
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
}
diff --git a/py/obj.h b/py/obj.h
index 381fcc1f25..cbd12fe862 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -34,6 +34,8 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
// - xxxx...xx10: a qstr, bits 2 and above are the value
// - xxxx...xx00: a pointer to an mp_obj_base_t
+// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
+#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
@@ -57,7 +59,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 3, 3, (mp_fun_3_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, (~((machine_uint_t)0)), (mp_fun_var_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, n_args_max, (mp_fun_var_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, 0, (~((machine_uint_t)0)), (mp_fun_kw_t)fun_name)
+#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, n_args_min, (~((machine_uint_t)0)), (mp_fun_kw_t)fun_name)
// These macros are used to declare and define constant staticmethond and classmethod objects
// You can put "static" in front of the definitions to make them local
@@ -83,7 +85,11 @@ typedef mp_obj_t (*mp_fun_t)(void);
typedef mp_obj_t (*mp_fun_var_t)(int n, const mp_obj_t *);
typedef mp_obj_t (*mp_fun_kw_t)(mp_obj_t, struct _mp_map_t*);
-typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o);
+typedef enum {
+ PRINT_STR, PRINT_REPR
+} mp_print_kind_t;
+
+typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);
typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, int n_args, const mp_obj_t *args); // args are in reverse order in the array
typedef mp_obj_t (*mp_call_n_fun_t)(mp_obj_t fun, int n_args, const mp_obj_t *args); // args are in reverse order in the array
typedef mp_obj_t (*mp_call_n_kw_fun_t)(mp_obj_t fun, int n_args, int n_kw, const mp_obj_t *args); // args are in reverse order in the array
@@ -196,6 +202,8 @@ mp_obj_t mp_obj_new_none(void);
mp_obj_t mp_obj_new_bool(bool value);
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
mp_obj_t mp_obj_new_int(machine_int_t value);
+mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
+mp_obj_t mp_obj_new_int_from_long_str(const char *s);
mp_obj_t mp_obj_new_str(qstr qstr);
#if MICROPY_ENABLE_FLOAT
mp_obj_t mp_obj_new_float(mp_float_t val);
@@ -226,8 +234,8 @@ mp_obj_t mp_obj_new_module(qstr module_name);
mp_obj_t mp_obj_get_type(mp_obj_t o_in);
const char *mp_obj_get_type_str(mp_obj_t o_in);
-void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in);
-void mp_obj_print(mp_obj_t o);
+void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
+void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
bool mp_obj_is_callable(mp_obj_t o_in);
machine_int_t mp_obj_hash(mp_obj_t o_in);
@@ -235,7 +243,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
bool mp_obj_less(mp_obj_t o1, mp_obj_t o2);
machine_int_t mp_obj_get_int(mp_obj_t arg);
-machine_int_t mp_obj_get_int_base(mp_obj_t arg, mp_obj_t base_arg);
+machine_int_t mp_obj_parse_int(mp_obj_t arg, mp_obj_t base_arg);
#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);
@@ -282,12 +290,23 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
// tuple
extern const mp_obj_type_t tuple_type;
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
+void mp_obj_tuple_del(mp_obj_t self_in);
// list
extern const mp_obj_type_t list_type;
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
+mp_obj_t mp_obj_list_sort(mp_obj_t args, struct _mp_map_t *kwargs);
+
+// map (the python builtin, not the dict implementation detail)
+extern const mp_obj_type_t map_type;
+
+// enumerate
+extern const mp_obj_type_t enumerate_type;
+
+// filter
+extern const mp_obj_type_t filter_type;
// dict
extern const mp_obj_type_t dict_type;
@@ -303,6 +322,10 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
extern const mp_obj_type_t slice_type;
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step);
+// zip
+extern const mp_obj_type_t zip_type;
+
+
// functions
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
mp_obj_base_t base;
diff --git a/py/objbool.c b/py/objbool.c
index da9a678063..66f9e902a6 100644
--- a/py/objbool.c
+++ b/py/objbool.c
@@ -13,7 +13,7 @@ typedef struct _mp_obj_bool_t {
bool value;
} mp_obj_bool_t;
-static void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_bool_t *self = self_in;
if (self->value) {
print(env, "True");
diff --git a/py/objcomplex.c b/py/objcomplex.c
index 1036bae420..bd103bbfab 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -21,7 +21,7 @@ typedef struct _mp_obj_complex_t {
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
-void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_complex_t *o = o_in;
if (o->real == 0) {
print(env, "%.8gj", o->imag);
diff --git a/py/objdict.c b/py/objdict.c
index 6dbb1f316b..da1b5b9f5b 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -20,7 +20,7 @@ typedef struct _mp_obj_dict_t {
static mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur);
static mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in);
-static void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_dict_t *self = self_in;
bool first = true;
print(env, "{");
@@ -31,9 +31,9 @@ static void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
print(env, ", ");
}
first = false;
- mp_obj_print_helper(print, env, next->key);
+ mp_obj_print_helper(print, env, next->key, PRINT_REPR);
print(env, ": ");
- mp_obj_print_helper(print, env, next->value);
+ mp_obj_print_helper(print, env, next->value, PRINT_REPR);
}
print(env, "}");
}
@@ -57,6 +57,12 @@ static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return elem->value;
}
}
+ case RT_COMPARE_OP_IN:
+ case RT_COMPARE_OP_NOT_IN:
+ {
+ mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
+ return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (elem == NULL));
+ }
default:
// op not supported
return NULL;
@@ -344,7 +350,7 @@ static mp_obj_t dict_view_getiter(mp_obj_t view_in) {
return o;
}
-static void dict_view_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void dict_view_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
assert(MP_OBJ_IS_TYPE(self_in, &dict_view_type));
mp_obj_dict_view_t *self = self_in;
bool first = true;
@@ -357,15 +363,25 @@ static void dict_view_print(void (*print)(void *env, const char *fmt, ...), void
print(env, ", ");
}
first = false;
- mp_obj_print_helper(print, env, next);
+ mp_obj_print_helper(print, env, next, PRINT_REPR);
}
print(env, "])");
}
+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 */
+ mp_obj_dict_view_t *o = lhs_in;
+ if (o->kind != MP_DICT_VIEW_KEYS) return NULL;
+ if (op != RT_COMPARE_OP_IN && op != RT_COMPARE_OP_NOT_IN) return NULL;
+ return dict_binary_op(op, o->dict, rhs_in);
+}
+
+
static const mp_obj_type_t dict_view_type = {
{ &mp_const_type },
"dict_view",
.print = dict_view_print,
+ .binary_op = dict_view_binary_op,
.getiter = dict_view_getiter,
};
diff --git a/py/objenumerate.c b/py/objenumerate.c
new file mode 100644
index 0000000000..5bfd8a3370
--- /dev/null
+++ b/py/objenumerate.c
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "obj.h"
+#include "runtime.h"
+
+typedef struct _mp_obj_enumerate_t {
+ mp_obj_base_t base;
+ mp_obj_t iter;
+ machine_int_t cur;
+} mp_obj_enumerate_t;
+
+static mp_obj_t enumerate_getiter(mp_obj_t self_in) {
+ return self_in;
+}
+
+static mp_obj_t enumerate_iternext(mp_obj_t self_in);
+
+/* TODO: enumerate is one of the ones that can take args or kwargs.
+ Sticking to args for now */
+static mp_obj_t enumerate_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+ /* NOTE: args are backwards */
+ assert(n_args > 0);
+ args += n_args - 1;
+ mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);
+ o->base.type = &enumerate_type;
+ o->iter = rt_getiter(args[0]);
+ o->cur = n_args > 1 ? mp_obj_get_int(args[-1]) : 0;
+
+ return o;
+}
+
+const mp_obj_type_t enumerate_type = {
+ { &mp_const_type },
+ "enumerate",
+ .make_new = enumerate_make_new,
+ .iternext = enumerate_iternext,
+ .getiter = enumerate_getiter,
+};
+
+static mp_obj_t enumerate_iternext(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &enumerate_type));
+ mp_obj_enumerate_t *self = self_in;
+ mp_obj_t next = rt_iternext(self->iter);
+ if (next == mp_const_stop_iteration) {
+ return mp_const_stop_iteration;
+ } else {
+ mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next};
+ return mp_obj_new_tuple(2, items);
+ }
+}
diff --git a/py/objexcept.c b/py/objexcept.c
index 4708a27bfc..67e6d63155 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -8,105 +8,98 @@
#include "misc.h"
#include "mpconfig.h"
#include "obj.h"
+#include "objtuple.h"
+// This is unified class for C-level and Python-level exceptions
+// Python-level exception have empty ->msg and all arguments are in
+// args tuple. C-level excepttion likely have ->msg, and may as well
+// have args tuple (or otherwise have it as NULL).
typedef struct mp_obj_exception_t {
mp_obj_base_t base;
qstr id;
- int n_args;
- const void *args[];
+ qstr msg;
+ mp_obj_tuple_t args;
} mp_obj_exception_t;
-void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_exception_t *o = o_in;
- switch (o->n_args) {
- case 0:
+ if (o->msg != 0) {
+ print(env, "%s: %s", qstr_str(o->id), qstr_str(o->msg));
+ } else {
+ // Yes, that's how CPython has it
+ if (kind == PRINT_REPR) {
print(env, "%s", qstr_str(o->id));
- break;
- case 1:
- print(env, "%s: %s", qstr_str(o->id), (const char*)o->args[0]);
- break;
- case 2:
- print(env, "%s: ", qstr_str(o->id));
- print(env, (const char*)o->args[0], o->args[1]);
- break;
- default: // here we just assume at least 3 args, but only use first 3
- print(env, "%s: ", qstr_str(o->id));
- print(env, (const char*)o->args[0], o->args[1], o->args[2]);
- break;
+ }
+ if (kind == PRINT_STR) {
+ if (o->args.len == 0) {
+ print(env, "");
+ return;
+ } else if (o->args.len == 1) {
+ mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
+ return;
+ }
+ }
+ tuple_print(print, env, &o->args, kind);
}
}
+// args in reversed order
+static mp_obj_t exception_call(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
+ mp_obj_exception_t *base = self_in;
+ mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, n_args);
+ o->base.type = &exception_type;
+ o->id = base->id;
+ o->msg = 0;
+ o->args.len = n_args;
+
+ // TODO: factor out as reusable copy_reversed()
+ int j = 0;
+ for (int i = n_args - 1; i >= 0; i--) {
+ o->args.items[i] = args[j++];
+ }
+ return o;
+}
+
const mp_obj_type_t exception_type = {
{ &mp_const_type },
"exception",
.print = exception_print,
+ .call_n = exception_call,
};
mp_obj_t mp_obj_new_exception(qstr id) {
- mp_obj_exception_t *o = m_new_obj(mp_obj_exception_t);
- o->base.type = &exception_type;
- o->id = id;
- o->n_args = 0;
- return o;
+ return mp_obj_new_exception_msg_varg(id, NULL);
}
mp_obj_t mp_obj_new_exception_msg(qstr id, const char *msg) {
- mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, 1);
- o->base.type = &exception_type;
- o->id = id;
- o->n_args = 1;
- o->args[0] = msg;
- return o;
+ return mp_obj_new_exception_msg_varg(id, msg);
}
mp_obj_t mp_obj_new_exception_msg_1_arg(qstr id, const char *fmt, const char *a1) {
- mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, 2);
- o->base.type = &exception_type;
- o->id = id;
- o->n_args = 2;
- o->args[0] = fmt;
- o->args[1] = a1;
- return o;
+ return mp_obj_new_exception_msg_varg(id, fmt, a1);
}
mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a1, const char *a2) {
- mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, 3);
- o->base.type = &exception_type;
- o->id = id;
- o->n_args = 3;
- o->args[0] = fmt;
- o->args[1] = a1;
- o->args[2] = a2;
- return o;
+ return mp_obj_new_exception_msg_varg(id, fmt, a1, a2);
}
mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
- // count number of arguments by number of % signs, excluding %%
- int n_args = 1; // count fmt
- for (const char *s = fmt; *s; s++) {
- if (*s == '%') {
- if (s[1] == '%') {
- s += 1;
- } else {
- n_args += 1;
- }
- }
- }
-
// make exception object
- mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, void*, n_args);
+ mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t*, 0);
o->base.type = &exception_type;
o->id = id;
- o->n_args = n_args;
- o->args[0] = fmt;
-
- // extract args and store them
- va_list ap;
- va_start(ap, fmt);
- for (int i = 1; i < n_args; i++) {
- o->args[i] = va_arg(ap, void*);
+ o->args.len = 0;
+ if (fmt == NULL) {
+ o->msg = 0;
+ } else {
+ // render exception message
+ vstr_t *vstr = vstr_new();
+ va_list ap;
+ va_start(ap, fmt);
+ vstr_vprintf(vstr, fmt, ap);
+ va_end(ap);
+ o->msg = qstr_from_str_take(vstr->buf, vstr->alloc);
}
- va_end(ap);
return o;
}
diff --git a/py/objfilter.c b/py/objfilter.c
new file mode 100644
index 0000000000..18225ac102
--- /dev/null
+++ b/py/objfilter.c
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "mpqstr.h"
+#include "obj.h"
+#include "runtime.h"
+
+typedef struct _mp_obj_filter_t {
+ mp_obj_base_t base;
+ mp_obj_t fun;
+ mp_obj_t iter;
+} mp_obj_filter_t;
+
+static mp_obj_t filter_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+ /* NOTE: args are backwards */
+ if (n_args != 2) {
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "filter expected 2 arguments"));
+ }
+ assert(n_args == 2);
+ mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t);
+ o->base.type = &filter_type;
+ o->fun = args[1];
+ o->iter = rt_getiter(args[0]);
+ return o;
+}
+
+static mp_obj_t filter_getiter(mp_obj_t self_in) {
+ return self_in;
+}
+
+static mp_obj_t filter_iternext(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &filter_type));
+ mp_obj_filter_t *self = self_in;
+ mp_obj_t next;
+ while ((next = rt_iternext(self->iter)) != mp_const_stop_iteration) {
+ mp_obj_t val;
+ if (self->fun != mp_const_none) {
+ val = rt_call_function_n(self->fun, 1, &next);
+ } else {
+ val = next;
+ }
+ if (rt_is_true(val)) {
+ return next;
+ }
+ }
+ return mp_const_stop_iteration;
+}
+
+const mp_obj_type_t filter_type = {
+ { &mp_const_type },
+ "filter",
+ .make_new = filter_make_new,
+ .getiter = filter_getiter,
+ .iternext = filter_iternext,
+};
diff --git a/py/objfloat.c b/py/objfloat.c
index bb44ac9549..1ac8754e40 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -19,7 +19,7 @@ typedef struct _mp_obj_float_t {
mp_obj_t mp_obj_new_float(mp_float_t value);
-static void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+static void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_float_t *o = o_in;
print(env, "%.8g", o->value);
}
diff --git a/py/objfun.c b/py/objfun.c
index afac3889fd..c624cf2d27 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -17,21 +17,44 @@
// mp_obj_fun_native_t defined in obj.h
+void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
+ if (n_kw && !self->is_kw) {
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
+ "function does not take keyword arguments"));
+ }
+
+ if (self->n_args_min == self->n_args_max) {
+ if (n_args != self->n_args_min) {
+ nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
+ "function takes %d positional arguments but %d were given",
+ (const char*)(machine_int_t)self->n_args_min,
+ (const char*)(machine_int_t)n_args));
+ }
+ } else {
+ if (n_args < self->n_args_min) {
+ nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError,
+ "<fun name>() missing %d required positional arguments: <list of names of params>",
+ (const char*)(machine_int_t)(self->n_args_min - n_args)));
+ } else if (n_args > self->n_args_max) {
+ nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
+ "<fun name> expected at most %d arguments, got %d",
+ (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
+ }
+ }
+}
+
mp_obj_t fun_native_call_n_kw(mp_obj_t self_in, int n_args, int n_kw, const mp_obj_t *args);
// args are in reverse order in the array
mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
mp_obj_fun_native_t *self = self_in;
+ // check number of arguments
+ check_nargs(self, n_args, 0);
if (self->is_kw) {
return fun_native_call_n_kw(self_in, n_args, 0, args);
}
if (self->n_args_min == self->n_args_max) {
// function requires a fixed number of arguments
- // check number of arguments
- if (n_args != self->n_args_min) {
- nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args_min, (const char*)(machine_int_t)n_args));
- }
-
// dispatch function call
switch (self->n_args_min) {
case 0:
@@ -54,12 +77,6 @@ mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
} else {
// function takes a variable number of arguments
- if (n_args < self->n_args_min) {
- nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "<fun name>() missing %d required positional arguments: <list of names of params>", (const char*)(machine_int_t)(self->n_args_min - n_args)));
- } else if (n_args > self->n_args_max) {
- nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "<fun name> expected at most %d arguments, got %d", (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
- }
-
// TODO really the args need to be passed in as a Python tuple, as the form f(*[1,2]) can be used to pass var args
mp_obj_t *args_ordered = m_new(mp_obj_t, n_args);
for (int i = 0; i < n_args; i++) {
@@ -76,9 +93,7 @@ mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
mp_obj_t fun_native_call_n_kw(mp_obj_t self_in, int n_args, int n_kw, const mp_obj_t *args) {
mp_obj_fun_native_t *self = self_in;
- if (!self->is_kw) {
- nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
- }
+ check_nargs(self, n_args, n_kw);
mp_obj_t *vargs = mp_obj_new_tuple_reverse(n_args, args + 2*n_kw);
mp_map_t *kw_args = mp_map_new(n_kw);
@@ -98,38 +113,13 @@ const mp_obj_type_t fun_native_type = {
.call_n_kw = fun_native_call_n_kw,
};
-mp_obj_t rt_make_function_0(mp_fun_0_t fun) {
- mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
- o->base.type = &fun_native_type;
- o->n_args_min = 0;
- o->n_args_max = 0;
- o->fun = fun;
- return o;
-}
-
-mp_obj_t rt_make_function_1(mp_fun_1_t fun) {
- mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
- o->base.type = &fun_native_type;
- o->n_args_min = 1;
- o->n_args_max = 1;
- o->fun = fun;
- return o;
-}
-
-mp_obj_t rt_make_function_2(mp_fun_2_t fun) {
- mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
- o->base.type = &fun_native_type;
- o->n_args_min = 2;
- o->n_args_max = 2;
- o->fun = fun;
- return o;
-}
-
-mp_obj_t rt_make_function_3(mp_fun_3_t fun) {
+// fun must have the correct signature for n_args fixed arguments
+mp_obj_t rt_make_function_n(int n_args, void *fun) {
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
o->base.type = &fun_native_type;
- o->n_args_min = 3;
- o->n_args_max = 3;
+ o->is_kw = false;
+ o->n_args_min = n_args;
+ o->n_args_max = n_args;
o->fun = fun;
return o;
}
@@ -137,6 +127,7 @@ mp_obj_t rt_make_function_3(mp_fun_3_t fun) {
mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun) {
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
o->base.type = &fun_native_type;
+ o->is_kw = false;
o->n_args_min = n_args_min;
o->n_args_max = ~((machine_uint_t)0);
o->fun = fun;
@@ -147,6 +138,7 @@ mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun) {
mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
o->base.type = &fun_native_type;
+ o->is_kw = false;
o->n_args_min = n_args_min;
o->n_args_max = n_args_max;
o->fun = fun;
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 7eeb4ef80b..40f202df3c 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -61,7 +61,7 @@ typedef struct _mp_obj_gen_instance_t {
mp_obj_t state[];
} mp_obj_gen_instance_t;
-void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
print(env, "<generator object 'fun-name' at %p>", self_in);
}
diff --git a/py/objint.c b/py/objint.c
index bd0926840b..937bff7ae3 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -8,21 +8,27 @@
#include "mpconfig.h"
#include "mpqstr.h"
#include "obj.h"
+#include "objint.h"
-typedef struct _mp_obj_int_t {
- mp_obj_base_t base;
-} mp_obj_int_t;
-
+// This dispatcher function is expected to be independent of the implementation
+// of long int
static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
switch (n_args) {
case 0:
return MP_OBJ_NEW_SMALL_INT(0);
case 1:
- return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
+ if (MP_OBJ_IS_TYPE(args[0], &str_type)) {
+ // a string, parse it
+ return MP_OBJ_NEW_SMALL_INT(strtonum(qstr_str(mp_obj_get_qstr(args[0])), 0));
+ } else {
+ return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
+ }
case 2:
- return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_base(args[1], args[0]));
+ // should be a string, parse it
+ // TODO proper error checking of argument types
+ return MP_OBJ_NEW_SMALL_INT(strtonum(qstr_str(mp_obj_get_qstr(args[1])), mp_obj_get_int(args[0])));
default:
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "int takes at most 2 arguments, %d given", (void*)(machine_int_t)n_args));
@@ -32,9 +38,45 @@ static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args)
const mp_obj_type_t int_type = {
{ &mp_const_type },
"int",
+ .print = int_print,
.make_new = int_make_new,
+ .binary_op = int_binary_op,
};
+#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+// This is called only for non-SMALL_INT
+void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+}
+
+// This is called only for non-SMALL_INT
+mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ assert(0);
+ return mp_const_none;
+}
+
+// This is called only with strings whose value doesn't fit in SMALL_INT
+mp_obj_t mp_obj_new_int_from_long_str(const char *s) {
+ assert(0);
+ return mp_const_none;
+}
+
+mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
+ // SMALL_INT accepts only signed numbers, of one bit less size
+ // then word size, which totals 2 bits less for unsigned numbers.
+ if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
+ return MP_OBJ_NEW_SMALL_INT(value);
+ }
+ // TODO: Raise exception
+ assert(0);
+ return mp_const_none;
+}
+
mp_obj_t mp_obj_new_int(machine_int_t value) {
- return MP_OBJ_NEW_SMALL_INT(value);
+ if (MP_OBJ_FITS_SMALL_INT(value)) {
+ return MP_OBJ_NEW_SMALL_INT(value);
+ }
+ // TODO: Raise exception
+ assert(0);
+ return mp_const_none;
}
+#endif
diff --git a/py/objint.h b/py/objint.h
new file mode 100644
index 0000000000..7d43971ec3
--- /dev/null
+++ b/py/objint.h
@@ -0,0 +1,9 @@
+typedef struct _mp_obj_int_t {
+ mp_obj_base_t base;
+#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+ mp_longint_impl_t val;
+#endif
+} mp_obj_int_t;
+
+void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
+mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
diff --git a/py/objlist.c b/py/objlist.c
index c153d2222b..829677b43b 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -26,14 +26,14 @@ static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in);
/******************************************************************************/
/* list */
-static void list_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+static void list_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_list_t *o = o_in;
print(env, "[");
for (int i = 0; i < o->len; i++) {
if (i > 0) {
print(env, ", ");
}
- mp_obj_print_helper(print, env, o->items[i]);
+ mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
}
print(env, "]");
}
@@ -62,6 +62,61 @@ static mp_obj_t list_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args
return NULL;
}
+// Don't pass RT_COMPARE_OP_NOT_EQUAL here
+static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &list_type));
+ if (!MP_OBJ_IS_TYPE(another_in, &list_type)) {
+ return false;
+ }
+ mp_obj_list_t *self = self_in;
+ mp_obj_list_t *another = another_in;
+ if (op == RT_COMPARE_OP_EQUAL && self->len != another->len) {
+ return false;
+ }
+
+ // Let's deal only with > & >=
+ if (op == RT_COMPARE_OP_LESS || op == RT_COMPARE_OP_LESS_EQUAL) {
+ mp_obj_t t = self;
+ self = another;
+ another = t;
+ if (op == RT_COMPARE_OP_LESS) {
+ op = RT_COMPARE_OP_MORE;
+ } else {
+ op = RT_COMPARE_OP_MORE_EQUAL;
+ }
+ }
+
+ int len = self->len < another->len ? self->len : another->len;
+ bool eq_status = true; // empty lists are equal
+ bool rel_status;
+ for (int i = 0; i < len; i++) {
+ eq_status = mp_obj_equal(self->items[i], another->items[i]);
+ if (op == RT_COMPARE_OP_EQUAL && !eq_status) {
+ return false;
+ }
+ rel_status = (rt_binary_op(op, self->items[i], another->items[i]) == mp_const_true);
+ if (!eq_status && !rel_status) {
+ return false;
+ }
+ }
+
+ // If we had tie in the last element...
+ if (eq_status) {
+ // ... and we have lists of different lengths...
+ if (self->len != another->len) {
+ if (self->len < another->len) {
+ // ... then longer list length wins (we deal only with >)
+ return false;
+ }
+ } else if (op == RT_COMPARE_OP_MORE) {
+ // Otherwise, if we have strict relation, equality means failure
+ return false;
+ }
+ }
+
+ return true;
+}
+
static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
mp_obj_list_t *o = lhs;
switch (op) {
@@ -105,6 +160,15 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
}
return s;
}
+ case RT_COMPARE_OP_EQUAL:
+ case RT_COMPARE_OP_LESS:
+ case RT_COMPARE_OP_LESS_EQUAL:
+ case RT_COMPARE_OP_MORE:
+ case RT_COMPARE_OP_MORE_EQUAL:
+ return MP_BOOL(list_cmp_helper(op, lhs, rhs));
+ case RT_COMPARE_OP_NOT_EQUAL:
+ return MP_BOOL(!list_cmp_helper(RT_COMPARE_OP_EQUAL, lhs, rhs));
+
default:
// op not supported
return NULL;
@@ -184,13 +248,14 @@ static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, bool r
}
}
-static mp_obj_t list_sort(mp_obj_t args, mp_map_t *kwargs) {
+mp_obj_t mp_obj_list_sort(mp_obj_t args, mp_map_t *kwargs) {
mp_obj_t *args_items = NULL;
uint args_len = 0;
assert(MP_OBJ_IS_TYPE(args, &tuple_type));
mp_obj_tuple_get(args, &args_len, &args_items);
assert(args_len >= 1);
+ assert(MP_OBJ_IS_TYPE(args_items[0], &list_type));
if (args_len > 1) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
"list.sort takes no positional arguments"));
@@ -316,7 +381,7 @@ static MP_DEFINE_CONST_FUN_OBJ_3(list_insert_obj, list_insert);
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_pop_obj, 1, 2, list_pop);
static MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, list_remove);
static MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse);
-static MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, list_sort);
+static MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 0, mp_obj_list_sort);
static const mp_method_t list_type_methods[] = {
{ "append", &list_append_obj },
diff --git a/py/objmap.c b/py/objmap.c
new file mode 100644
index 0000000000..365735283a
--- /dev/null
+++ b/py/objmap.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "mpqstr.h"
+#include "obj.h"
+#include "runtime.h"
+
+typedef struct _mp_obj_map_t {
+ mp_obj_base_t base;
+ machine_uint_t n_iters;
+ mp_obj_t fun;
+ mp_obj_t iters[];
+} mp_obj_map_t;
+
+static mp_obj_t map_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+ /* NOTE: args are backwards */
+ if (n_args < 2) {
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "map must have at least 2 arguments"));
+ }
+ assert(n_args >= 2);
+ mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1);
+ o->base.type = &map_type;
+ o->n_iters = n_args - 1;
+ o->fun = args[n_args - 1];
+ for (int i = 0; i < n_args - 1; i++) {
+ o->iters[i] = rt_getiter(args[n_args-i-2]);
+ }
+ 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, &map_type));
+ mp_obj_map_t *self = self_in;
+ mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters);
+
+ for (int i = 0; i < self->n_iters; i++) {
+ mp_obj_t next = rt_iternext(self->iters[i]);
+ if (next == mp_const_stop_iteration) {
+ m_del(mp_obj_t, nextses, self->n_iters);
+ return mp_const_stop_iteration;
+ }
+ nextses[i] = next;
+ }
+ return rt_call_function_n(self->fun, self->n_iters, nextses);
+}
+
+const mp_obj_type_t map_type = {
+ { &mp_const_type },
+ "map",
+ .make_new = map_make_new,
+ .getiter = map_getiter,
+ .iternext = map_iternext,
+};
diff --git a/py/objmodule.c b/py/objmodule.c
index ade9369176..50d2bb35ed 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -17,7 +17,7 @@ typedef struct _mp_obj_module_t {
mp_map_t *globals;
} mp_obj_module_t;
-static void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_module_t *self = self_in;
print(env, "<module '%s' from '-unknown-file-'>", qstr_str(self->name));
}
diff --git a/py/objnone.c b/py/objnone.c
index c0efe6c0f5..84d0ba164c 100644
--- a/py/objnone.c
+++ b/py/objnone.c
@@ -10,7 +10,7 @@ typedef struct _mp_obj_none_t {
mp_obj_base_t base;
} mp_obj_none_t;
-void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
print(env, "None");
}
diff --git a/py/objset.c b/py/objset.c
index 67dab11dfb..6ea6d62d8f 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <assert.h>
#include "nlr.h"
@@ -8,6 +9,7 @@
#include "mpqstr.h"
#include "obj.h"
#include "runtime.h"
+#include "runtime0.h"
#include "map.h"
typedef struct _mp_obj_set_t {
@@ -15,8 +17,20 @@ typedef struct _mp_obj_set_t {
mp_set_t set;
} mp_obj_set_t;
-void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+typedef struct _mp_obj_set_it_t {
+ mp_obj_base_t base;
+ mp_obj_set_t *set;
+ machine_uint_t cur;
+} mp_obj_set_it_t;
+
+static mp_obj_t set_it_iternext(mp_obj_t self_in);
+
+void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_set_t *self = self_in;
+ if (self->set.used == 0) {
+ print(env, "set()");
+ return;
+ }
bool first = true;
print(env, "{");
for (int i = 0; i < self->set.alloc; i++) {
@@ -25,12 +39,13 @@ void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj
print(env, ", ");
}
first = false;
- mp_obj_print_helper(print, env, self->set.table[i]);
+ mp_obj_print_helper(print, env, self->set.table[i], PRINT_REPR);
}
}
print(env, "}");
}
+
static mp_obj_t set_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
switch (n_args) {
case 0:
@@ -54,11 +69,389 @@ static mp_obj_t set_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args)
}
}
+const mp_obj_type_t set_it_type = {
+ { &mp_const_type },
+ "set_iterator",
+ .iternext = set_it_iternext,
+};
+
+static mp_obj_t set_it_iternext(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_it_type));
+ mp_obj_set_it_t *self = self_in;
+ machine_uint_t max = self->set->set.alloc;
+ mp_obj_t *table = self->set->set.table;
+
+ for (machine_uint_t i = self->cur; i < max; i++) {
+ if (table[i] != NULL) {
+ self->cur = i + 1;
+ return table[i];
+ }
+ }
+
+ return mp_const_stop_iteration;
+}
+
+static mp_obj_t set_getiter(mp_obj_t set_in) {
+ mp_obj_set_it_t *o = m_new_obj(mp_obj_set_it_t);
+ o->base.type = &set_it_type;
+ o->set = (mp_obj_set_t *)set_in;
+ o->cur = 0;
+ return o;
+}
+
+
+/******************************************************************************/
+/* set methods */
+
+static mp_obj_t set_add(mp_obj_t self_in, mp_obj_t item) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+ mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add);
+
+static mp_obj_t set_clear(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+
+ mp_set_clear(&self->set);
+
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear);
+
+static mp_obj_t set_copy(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+
+ mp_obj_set_t *other = m_new_obj(mp_obj_set_t);
+ other->base.type = &set_type;
+ mp_set_init(&other->set, self->set.alloc - 1);
+ other->set.used = self->set.used;
+ memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t));
+
+ return other;
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy);
+
+static mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+ mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard);
+
+static mp_obj_t set_diff_int(int n_args, const mp_obj_t *args, bool update) {
+ assert(n_args > 0);
+ assert(MP_OBJ_IS_TYPE(args[0], &set_type));
+ mp_obj_set_t *self;
+ if (update) {
+ self = args[0];
+ } else {
+ self = set_copy(args[0]);
+ }
+
+
+ for (int i = 1; i < n_args; i++) {
+ mp_obj_t other = args[i];
+ if (self == other) {
+ set_clear(self);
+ } else {
+ mp_obj_t iter = rt_getiter(other);
+ mp_obj_t next;
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ set_discard(self, next);
+ }
+ }
+ }
+
+ return self;
+}
+
+static mp_obj_t set_diff(int n_args, const mp_obj_t *args) {
+ return set_diff_int(n_args, args, false);
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_obj, 1, set_diff);
+
+static mp_obj_t set_diff_update(int n_args, const mp_obj_t *args) {
+ set_diff_int(n_args, args, true);
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_update_obj, 1, set_diff_update);
+
+static mp_obj_t set_intersect_int(mp_obj_t self_in, mp_obj_t other, bool update) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ if (self_in == other) {
+ return update ? mp_const_none : set_copy(self_in);
+ }
+
+ mp_obj_set_t *self = self_in;
+ mp_obj_set_t *out = mp_obj_new_set(0, NULL);
+
+ mp_obj_t iter = rt_getiter(other);
+ mp_obj_t next;
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {
+ set_add(out, next);
+ }
+ }
+
+ if (update) {
+ m_del(mp_obj_t, self->set.table, self->set.alloc);
+ self->set.alloc = out->set.alloc;
+ self->set.used = out->set.used;
+ self->set.table = out->set.table;
+ }
+
+ return update ? mp_const_none : out;
+}
+
+static mp_obj_t set_intersect(mp_obj_t self_in, mp_obj_t other) {
+ return set_intersect_int(self_in, other, false);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_obj, set_intersect);
+
+static mp_obj_t set_intersect_update(mp_obj_t self_in, mp_obj_t other) {
+ return set_intersect_int(self_in, other, true);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_update_obj, set_intersect_update);
+
+static mp_obj_t set_isdisjoint(mp_obj_t self_in, mp_obj_t other) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+
+ mp_obj_t iter = rt_getiter(other);
+ mp_obj_t next;
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {
+ return mp_const_false;
+ }
+ }
+ return mp_const_true;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_isdisjoint_obj, set_isdisjoint);
+
+static mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool proper) {
+ mp_obj_set_t *self;
+ bool cleanup_self = false;
+ if (MP_OBJ_IS_TYPE(self_in, &set_type)) {
+ self = self_in;
+ } else {
+ self = set_make_new(NULL, 1, &self_in);
+ cleanup_self = true;
+ }
+
+ mp_obj_set_t *other;
+ bool cleanup_other = false;
+ if (MP_OBJ_IS_TYPE(other_in, &set_type)) {
+ other = other_in;
+ } else {
+ other = set_make_new(NULL, 1, &other_in);
+ cleanup_other = true;
+ }
+ bool out = true;
+ if (proper && self->set.used == other->set.used) {
+ out = false;
+ } else {
+ mp_obj_t iter = set_getiter(self);
+ mp_obj_t next;
+ while ((next = set_it_iternext(iter)) != mp_const_stop_iteration) {
+ if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) {
+ out = false;
+ break;
+ }
+ }
+ }
+ if (cleanup_self) {
+ set_clear(self);
+ }
+ if (cleanup_other) {
+ set_clear(other);
+ }
+ return MP_BOOL(out);
+}
+static mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) {
+ return set_issubset_internal(self_in, other_in, false);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_issubset_obj, set_issubset);
+
+static mp_obj_t set_issubset_proper(mp_obj_t self_in, mp_obj_t other_in) {
+ return set_issubset_internal(self_in, other_in, true);
+}
+
+static mp_obj_t set_issuperset(mp_obj_t self_in, mp_obj_t other_in) {
+ return set_issubset_internal(other_in, self_in, false);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_issuperset_obj, set_issuperset);
+
+static mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) {
+ return set_issubset_internal(other_in, self_in, true);
+}
+
+static mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+ if (!MP_OBJ_IS_TYPE(other_in, &set_type)) {
+ return mp_const_false;
+ }
+ mp_obj_set_t *other = other_in;
+ if (self->set.used != other->set.used) {
+ return mp_const_false;
+ }
+ return set_issubset(self_in, other_in);
+}
+
+static mp_obj_t set_pop(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+
+ if (self->set.used == 0) {
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "pop from an empty set"));
+ }
+ mp_obj_t obj = mp_set_lookup(&self->set, NULL,
+ MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_FIRST);
+ return obj;
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop);
+
+static mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+ if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) {
+ nlr_jump(mp_obj_new_exception(MP_QSTR_KeyError));
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove);
+
+static mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = self_in;
+ mp_obj_t iter = rt_getiter(other_in);
+ mp_obj_t next;
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update);
+
+static mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ self_in = set_copy(self_in);
+ set_symmetric_difference_update(self_in, other_in);
+ return self_in;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference);
+
+static void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) {
+ mp_obj_t iter = rt_getiter(other_in);
+ mp_obj_t next;
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ }
+}
+
+static mp_obj_t set_update(int n_args, const mp_obj_t *args) {
+ assert(n_args > 0);
+ assert(MP_OBJ_IS_TYPE(args[0], &set_type));
+
+ for (int i = 1; i < n_args; i++) {
+ set_update_int(args[0], args[i]);
+ }
+
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR(set_update_obj, 1, set_update);
+
+static mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &set_type));
+ mp_obj_set_t *self = set_copy(self_in);
+ set_update_int(self, other_in);
+ return self;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union);
+
+
+static mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
+ mp_obj_t args[] = {lhs, rhs};
+ switch (op) {
+ case RT_BINARY_OP_OR:
+ return set_union(lhs, rhs);
+ case RT_BINARY_OP_XOR:
+ return set_symmetric_difference(lhs, rhs);
+ case RT_BINARY_OP_AND:
+ return set_intersect(lhs, rhs);
+ case RT_BINARY_OP_SUBTRACT:
+ return set_diff(2, args);
+ case RT_BINARY_OP_INPLACE_OR:
+ return set_union(lhs, rhs);
+ case RT_BINARY_OP_INPLACE_XOR:
+ return set_symmetric_difference(lhs, rhs);
+ case RT_BINARY_OP_INPLACE_AND:
+ return set_intersect(lhs, rhs);
+ case RT_BINARY_OP_INPLACE_SUBTRACT:
+ return set_diff(2, args);
+ case RT_COMPARE_OP_LESS:
+ return set_issubset_proper(lhs, rhs);
+ case RT_COMPARE_OP_MORE:
+ return set_issuperset_proper(lhs, rhs);
+ case RT_COMPARE_OP_EQUAL:
+ return set_equal(lhs, rhs);
+ case RT_COMPARE_OP_LESS_EQUAL:
+ return set_issubset(lhs, rhs);
+ case RT_COMPARE_OP_MORE_EQUAL:
+ return set_issuperset(lhs, rhs);
+ case RT_COMPARE_OP_NOT_EQUAL:
+ return MP_BOOL(set_equal(lhs, rhs) == mp_const_false);
+ case RT_COMPARE_OP_IN:
+ case RT_COMPARE_OP_NOT_IN:
+ {
+ mp_obj_set_t *o = lhs;
+ mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP);
+ return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (elem == NULL));
+ }
+ default:
+ // op not supported
+ return NULL;
+ }
+}
+
+/******************************************************************************/
+/* set constructors & public C API */
+
+
+static const mp_method_t set_type_methods[] = {
+ { "add", &set_add_obj },
+ { "clear", &set_clear_obj },
+ { "copy", &set_copy_obj },
+ { "discard", &set_discard_obj },
+ { "difference", &set_diff_obj },
+ { "difference_update", &set_diff_update_obj },
+ { "intersection", &set_intersect_obj },
+ { "intersection_update", &set_intersect_update_obj },
+ { "isdisjoint", &set_isdisjoint_obj },
+ { "issubset", &set_issubset_obj },
+ { "issuperset", &set_issuperset_obj },
+ { "pop", &set_pop_obj },
+ { "remove", &set_remove_obj },
+ { "symmetric_difference", &set_symmetric_difference_obj },
+ { "symmetric_difference_update", &set_symmetric_difference_update_obj },
+ { "union", &set_union_obj },
+ { "update", &set_update_obj },
+ { NULL, NULL }, // end-of-list sentinel
+};
+
const mp_obj_type_t set_type = {
{ &mp_const_type },
"set",
.print = set_print,
.make_new = set_make_new,
+ .binary_op = set_binary_op,
+ .getiter = set_getiter,
+ .methods = set_type_methods,
};
mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) {
@@ -66,7 +459,7 @@ mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) {
o->base.type = &set_type;
mp_set_init(&o->set, n_args);
for (int i = 0; i < n_args; i++) {
- mp_set_lookup(&o->set, items[i], true);
+ mp_set_lookup(&o->set, items[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
return o;
}
@@ -74,5 +467,5 @@ mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) {
void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {
assert(MP_OBJ_IS_TYPE(self_in, &set_type));
mp_obj_set_t *self = self_in;
- mp_set_lookup(&self->set, item, true);
+ mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
diff --git a/py/objslice.c b/py/objslice.c
index d95ccef06f..8abcea08d0 100644
--- a/py/objslice.c
+++ b/py/objslice.c
@@ -16,7 +16,7 @@ typedef struct _mp_obj_ellipsis_t {
mp_obj_base_t base;
} mp_obj_ellipsis_t;
-void ellipsis_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+void ellipsis_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
print(env, "Ellipsis");
}
@@ -42,7 +42,7 @@ typedef struct _mp_obj_slice_t {
machine_int_t stop;
} mp_obj_slice_t;
-void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_slice_t *o = o_in;
print(env, "slice(" INT_FMT ", " INT_FMT ")", o->start, o->stop);
}
diff --git a/py/objstr.c b/py/objstr.c
index ea4f5ead24..0621a8df75 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -22,10 +22,14 @@ static mp_obj_t mp_obj_new_str_iterator(mp_obj_str_t *str, int cur);
/******************************************************************************/
/* str */
-void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_str_t *self = self_in;
- // TODO need to escape chars etc
- print(env, "'%s'", qstr_str(self->qstr));
+ if (kind == PRINT_STR) {
+ print(env, "%s", qstr_str(self->qstr));
+ } else {
+ // TODO need to escape chars etc
+ print(env, "'%s'", qstr_str(self->qstr));
+ }
}
mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
@@ -85,6 +89,15 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return mp_obj_new_str(qstr_from_str_take(val, alloc_len));
}
break;
+ case RT_COMPARE_OP_IN:
+ case RT_COMPARE_OP_NOT_IN:
+ /* NOTE `a in b` is `b.__contains__(a)` */
+ if (MP_OBJ_IS_TYPE(rhs_in, &str_type)) {
+ const char *rhs_str = qstr_str(((mp_obj_str_t*)rhs_in)->qstr);
+ /* FIXME \0 in strs */
+ return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (strstr(lhs_str, rhs_str) == NULL));
+ }
+ break;
}
return MP_OBJ_NULL; // op not supported
@@ -156,6 +169,46 @@ static bool chr_in_str(const char* const str, const size_t str_len, const char c
return false;
}
+static mp_obj_t str_find(int n_args, const mp_obj_t *args) {
+ assert(2 <= n_args && n_args <= 4);
+ assert(MP_OBJ_IS_TYPE(args[0], &str_type));
+ if (!MP_OBJ_IS_TYPE(args[1], &str_type)) {
+ nlr_jump(mp_obj_new_exception_msg_1_arg(
+ MP_QSTR_TypeError,
+ "Can't convert '%s' object to str implicitly",
+ mp_obj_get_type_str(args[1])));
+ }
+
+ const char* haystack = qstr_str(((mp_obj_str_t*)args[0])->qstr);
+ const char* needle = qstr_str(((mp_obj_str_t*)args[1])->qstr);
+
+ size_t haystack_len = strlen(haystack);
+ size_t needle_len = strlen(needle);
+
+ size_t start = 0;
+ size_t end = haystack_len;
+ /* TODO use a non-exception-throwing mp_get_index */
+ if (n_args >= 3 && args[2] != mp_const_none) {
+ start = mp_get_index(&str_type, haystack_len, args[2]);
+ }
+ if (n_args >= 4 && args[3] != mp_const_none) {
+ end = mp_get_index(&str_type, haystack_len, args[3]);
+ }
+
+ char *p = strstr(haystack + start, needle);
+ if (p == NULL) {
+ // not found
+ return MP_OBJ_NEW_SMALL_INT(-1);
+ } else {
+ // found
+ machine_int_t pos = p - haystack;
+ if (pos + needle_len > end) {
+ pos = -1;
+ }
+ return MP_OBJ_NEW_SMALL_INT(pos);
+ }
+}
+
mp_obj_t str_strip(int n_args, const mp_obj_t *args) {
assert(1 <= n_args && n_args <= 2);
assert(MP_OBJ_IS_TYPE(args[0], &str_type));
@@ -205,13 +258,6 @@ mp_obj_t str_strip(int n_args, const mp_obj_t *args) {
return mp_obj_new_str(qstr_from_str_take(stripped_str, stripped_len + 1));
}
-void vstr_printf_wrapper(void *env, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vstr_vprintf(env, fmt, args);
- va_end(args);
-}
-
mp_obj_t str_format(int n_args, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(args[0], &str_type));
mp_obj_str_t *self = args[0];
@@ -228,7 +274,8 @@ mp_obj_t str_format(int n_args, const mp_obj_t *args) {
if (arg_i >= n_args) {
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_IndexError, "tuple index out of range"));
}
- mp_obj_print_helper(vstr_printf_wrapper, vstr, args[arg_i]);
+ // TODO: may be PRINT_REPR depending on formatting code
+ mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_STR);
arg_i++;
}
} else {
@@ -239,11 +286,13 @@ mp_obj_t str_format(int n_args, const mp_obj_t *args) {
return mp_obj_new_str(qstr_from_str_take(vstr->buf, vstr->alloc));
}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);
static MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
static MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, str_format);
static const mp_method_t str_type_methods[] = {
+ { "find", &str_find_obj },
{ "join", &str_join_obj },
{ "strip", &str_strip_obj },
{ "format", &str_format_obj },
diff --git a/py/objtuple.c b/py/objtuple.c
index 7685cc449f..a64b1fa16c 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -9,26 +9,21 @@
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
-
-typedef struct _mp_obj_tuple_t {
- mp_obj_base_t base;
- machine_uint_t len;
- mp_obj_t items[];
-} mp_obj_tuple_t;
+#include "objtuple.h"
static mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, int cur);
/******************************************************************************/
/* tuple */
-static void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_tuple_t *o = o_in;
print(env, "(");
for (int i = 0; i < o->len; i++) {
if (i > 0) {
print(env, ", ");
}
- mp_obj_print_helper(print, env, o->items[i]);
+ mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
}
if (o->len == 1) {
print(env, ",");
@@ -116,8 +111,10 @@ mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items) {
mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n);
o->base.type = &tuple_type;
o->len = n;
- for (int i = 0; i < n; i++) {
- o->items[i] = items[i];
+ if (items) {
+ for (int i = 0; i < n; i++) {
+ o->items[i] = items[i];
+ }
}
return o;
}
@@ -138,8 +135,18 @@ mp_obj_t mp_obj_new_tuple_reverse(uint n, const mp_obj_t *items) {
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items) {
assert(MP_OBJ_IS_TYPE(self_in, &tuple_type));
mp_obj_tuple_t *self = self_in;
- *len = self->len;
- *items = &self->items[0];
+ if (len) {
+ *len = self->len;
+ }
+ if (items) {
+ *items = &self->items[0];
+ }
+}
+
+void mp_obj_tuple_del(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &tuple_type));
+ mp_obj_tuple_t *self = self_in;
+ m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self);
}
/******************************************************************************/
diff --git a/py/objtuple.h b/py/objtuple.h
new file mode 100644
index 0000000000..6ff38c10eb
--- /dev/null
+++ b/py/objtuple.h
@@ -0,0 +1,7 @@
+typedef struct _mp_obj_tuple_t {
+ mp_obj_base_t base;
+ machine_uint_t len;
+ mp_obj_t items[];
+} mp_obj_tuple_t;
+
+void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
diff --git a/py/objtype.c b/py/objtype.c
index 011ee43552..5a2f96d6b0 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -66,7 +66,7 @@ static mp_map_elem_t *mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr,
}
}
-static void class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in);
}
@@ -148,7 +148,7 @@ static bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
// - there is a constant mp_obj_type_t (called mp_const_type) for the 'type' object
// - creating a new class (a new type) creates a new mp_obj_type_t
-static void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+static void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_type_t *self = self_in;
print(env, "<class '%s'>", self->name);
}
diff --git a/py/objzip.c b/py/objzip.c
new file mode 100644
index 0000000000..a552ff5881
--- /dev/null
+++ b/py/objzip.c
@@ -0,0 +1,57 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "obj.h"
+#include "runtime.h"
+
+typedef struct _mp_obj_zip_t {
+ mp_obj_base_t base;
+ int n_iters;
+ mp_obj_t iters[];
+} mp_obj_zip_t;
+
+static mp_obj_t zip_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
+ /* NOTE: args are backwards */
+ mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args);
+ o->base.type = &zip_type;
+ o->n_iters = n_args;
+ for (int i = 0; i < n_args; i++) {
+ o->iters[i] = rt_getiter(args[n_args-i-1]);
+ }
+ return o;
+}
+
+static mp_obj_t zip_getiter(mp_obj_t self_in) {
+ return self_in;
+}
+
+static mp_obj_t zip_iternext(mp_obj_t self_in) {
+ assert(MP_OBJ_IS_TYPE(self_in, &zip_type));
+ mp_obj_zip_t *self = self_in;
+ mp_obj_t *items;
+ if (self->n_iters == 0) {
+ return mp_const_stop_iteration;
+ }
+ mp_obj_t o = mp_obj_new_tuple(self->n_iters, NULL);
+ mp_obj_tuple_get(o, NULL, &items);
+
+ for (int i = 0; i < self->n_iters; i++) {
+ mp_obj_t next = rt_iternext(self->iters[i]);
+ if (next == mp_const_stop_iteration) {
+ mp_obj_tuple_del(o);
+ return mp_const_stop_iteration;
+ }
+ items[i] = next;
+ }
+ return o;
+}
+
+const mp_obj_type_t zip_type = {
+ { &mp_const_type },
+ "zip",
+ .make_new = zip_make_new,
+ .getiter = zip_getiter,
+ .iternext = zip_iternext,
+};
diff --git a/py/parse.c b/py/parse.c
index d3786ba956..49b42e5d77 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -8,6 +8,7 @@
#include "misc.h"
#include "mpconfig.h"
+#include "mpqstr.h"
#include "lexer.h"
#include "parse.h"
@@ -88,6 +89,7 @@ typedef struct _parser_t {
uint rule_stack_top;
rule_stack_t *rule_stack;
+ uint result_stack_alloc;
uint result_stack_top;
mp_parse_node_t *result_stack;
} parser_t;
@@ -121,7 +123,7 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
int num_parse_nodes_allocated = 0;
mp_parse_node_struct_t *parse_node_new_struct(int rule_id, int num_args) {
- mp_parse_node_struct_t *pn = m_malloc(sizeof(mp_parse_node_struct_t) + num_args * sizeof(mp_parse_node_t));
+ mp_parse_node_struct_t *pn = m_new_obj_var(mp_parse_node_struct_t, mp_parse_node_t, num_args);
pn->source = 0; // TODO
pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);
num_parse_nodes_allocated += 1;
@@ -180,6 +182,10 @@ static mp_parse_node_t peek_result(parser_t *parser, int pos) {
}
static void push_result_node(parser_t *parser, mp_parse_node_t pn) {
+ if (parser->result_stack_top >= parser->result_stack_alloc) {
+ parser->result_stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2);
+ parser->result_stack_alloc *= 2;
+ }
parser->result_stack[parser->result_stack_top++] = pn;
}
@@ -191,7 +197,7 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
} else if (tok->kind == MP_TOKEN_NUMBER) {
bool dec = false;
bool small_int = true;
- int int_val = 0;
+ machine_int_t int_val = 0;
int len = tok->len;
const char *str = tok->str;
int base = 10;
@@ -211,7 +217,9 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
i = 2;
}
}
+ bool overflow = false;
for (; i < len; i++) {
+ machine_int_t old_val = int_val;
if (unichar_isdigit(str[i]) && str[i] - '0' < base) {
int_val = base * int_val + str[i] - '0';
} else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') {
@@ -225,10 +233,17 @@ static void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
small_int = false;
break;
}
+ if (int_val < old_val) {
+ // If new value became less than previous, it's overflow
+ overflow = true;
+ } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
+ // If signed number changed sign - it's overflow
+ overflow = true;
+ }
}
if (dec) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn_copy(str, len));
- } else if (small_int && MP_FIT_SMALL_INT(int_val)) {
+ } else if (small_int && !overflow && MP_FIT_SMALL_INT(int_val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val);
} else {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn_copy(str, len));
@@ -251,23 +266,31 @@ static void push_result_rule(parser_t *parser, const rule_t *rule, int num_args)
push_result_node(parser, (mp_parse_node_t)pn);
}
-mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
- parser_t *parser = m_new(parser_t, 1);
+mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr *exc_id_out, const char **exc_msg_out) {
+
+ // allocate memory for the parser and its stacks
+
+ parser_t *parser = m_new_obj(parser_t);
+
parser->rule_stack_alloc = 64;
parser->rule_stack_top = 0;
parser->rule_stack = m_new(rule_stack_t, parser->rule_stack_alloc);
- parser->result_stack = m_new(mp_parse_node_t, 1000);
+ parser->result_stack_alloc = 64;
parser->result_stack_top = 0;
+ parser->result_stack = m_new(mp_parse_node_t, parser->result_stack_alloc);
+ // work out the top-level rule to use, and push it on the stack
int top_level_rule;
switch (input_kind) {
case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break;
- //case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
+ case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
default: top_level_rule = RULE_file_input;
}
push_rule(parser, rules[top_level_rule], 0);
+ // parse!
+
uint n, i;
bool backtrack = false;
const rule_t *rule;
@@ -558,22 +581,39 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
//printf("--------------\n");
//result_stack_show(parser);
- assert(parser->result_stack_top == 1);
- //printf("maximum depth: %d\n", parser->rule_stack_alloc);
+ //printf("rule stack alloc: %d\n", parser->rule_stack_alloc);
+ //printf("result stack alloc: %d\n", parser->result_stack_alloc);
//printf("number of parse nodes allocated: %d\n", num_parse_nodes_allocated);
- return parser->result_stack[0];
+
+ // get the root parse node that we created
+ assert(parser->result_stack_top == 1);
+ mp_parse_node_t result = parser->result_stack[0];
+
+finished:
+ // free the memory that we don't need anymore
+ m_del(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc);
+ m_del(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc);
+ m_del_obj(parser_t, parser);
+
+ // return the result
+ return result;
syntax_error:
if (mp_lexer_is_kind(lex, MP_TOKEN_INDENT)) {
- mp_lexer_show_error_pythonic(lex, "IndentationError: unexpected indent");
+ *exc_id_out = MP_QSTR_IndentationError;
+ *exc_msg_out = "unexpected indent";
} else if (mp_lexer_is_kind(lex, MP_TOKEN_DEDENT_MISMATCH)) {
- mp_lexer_show_error_pythonic(lex, "IndentationError: unindent does not match any outer indentation level");
+ *exc_id_out = MP_QSTR_IndentationError;
+ *exc_msg_out = "unindent does not match any outer indentation level";
} else {
- mp_lexer_show_error_pythonic(lex, "syntax error:");
+ *exc_id_out = MP_QSTR_SyntaxError;
+ *exc_msg_out = "invalid syntax";
#ifdef USE_RULE_NAME
- mp_lexer_show_error(lex, rule->rule_name);
-#endif
+ // debugging: print the rule name that failed and the token
+ mp_lexer_show_error_pythonic(lex, rule->rule_name);
mp_token_show(mp_lexer_cur(lex));
+#endif
}
- return MP_PARSE_NODE_NULL;
+ result = MP_PARSE_NODE_NULL;
+ goto finished;
}
diff --git a/py/parse.h b/py/parse.h
index 7326243ea4..be2073ae5d 100644
--- a/py/parse.h
+++ b/py/parse.h
@@ -62,4 +62,5 @@ typedef enum {
MP_PARSE_EVAL_INPUT,
} mp_parse_input_kind_t;
-mp_parse_node_t mp_parse(struct _mp_lexer_t *lex, mp_parse_input_kind_t input_kind);
+// returns MP_PARSE_NODE_NULL on error, and then exc_id_out and exc_msg_out are valid
+mp_parse_node_t mp_parse(struct _mp_lexer_t *lex, mp_parse_input_kind_t input_kind, qstr *exc_id_out, const char **exc_msg_out);
diff --git a/py/py.mk b/py/py.mk
index c65fb5e65a..61f14f7bb3 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -78,12 +78,15 @@ PY_O_BASENAME = \
objclosure.o \
objcomplex.o \
objdict.o \
+ objenumerate.o \
objexcept.o \
+ objfilter.o \
objfloat.o \
objfun.o \
objgenerator.o \
objint.o \
objlist.o \
+ objmap.o \
objmodule.o \
objnone.o \
objrange.o \
@@ -95,9 +98,11 @@ PY_O_BASENAME = \
stream.o \
builtin.o \
builtinimport.o \
+ builtineval.o \
vm.o \
showbc.o \
repl.o \
+ objzip.o \
# prepend the build destination prefix to the py object files
diff --git a/py/runtime.c b/py/runtime.c
index b982ee32d0..e1e9e31cc7 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -90,13 +90,14 @@ void rt_init(void) {
mp_map_add_qstr(&map_builtins, MP_QSTR_SyntaxError, mp_obj_new_exception(MP_QSTR_SyntaxError));
mp_map_add_qstr(&map_builtins, MP_QSTR_ValueError, mp_obj_new_exception(MP_QSTR_ValueError));
mp_map_add_qstr(&map_builtins, MP_QSTR_OSError, mp_obj_new_exception(MP_QSTR_OSError));
+ mp_map_add_qstr(&map_builtins, MP_QSTR_AssertionError, mp_obj_new_exception(MP_QSTR_AssertionError));
// built-in objects
mp_map_add_qstr(&map_builtins, MP_QSTR_Ellipsis, mp_const_ellipsis);
// built-in core functions
mp_map_add_qstr(&map_builtins, MP_QSTR___build_class__, (mp_obj_t)&mp_builtin___build_class___obj);
- mp_map_add_qstr(&map_builtins, MP_QSTR___repl_print__, rt_make_function_1(mp_builtin___repl_print__));
+ mp_map_add_qstr(&map_builtins, MP_QSTR___repl_print__, (mp_obj_t)&mp_builtin___repl_print___obj);
// built-in types
mp_map_add_qstr(&map_builtins, MP_QSTR_bool, (mp_obj_t)&bool_type);
@@ -104,35 +105,43 @@ void rt_init(void) {
mp_map_add_qstr(&map_builtins, MP_QSTR_complex, (mp_obj_t)&complex_type);
#endif
mp_map_add_qstr(&map_builtins, MP_QSTR_dict, (mp_obj_t)&dict_type);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_enumerate, (mp_obj_t)&enumerate_type);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_filter, (mp_obj_t)&filter_type);
#if MICROPY_ENABLE_FLOAT
mp_map_add_qstr(&map_builtins, MP_QSTR_float, (mp_obj_t)&float_type);
#endif
mp_map_add_qstr(&map_builtins, MP_QSTR_int, (mp_obj_t)&int_type);
mp_map_add_qstr(&map_builtins, MP_QSTR_list, (mp_obj_t)&list_type);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_map, (mp_obj_t)&map_type);
mp_map_add_qstr(&map_builtins, MP_QSTR_set, (mp_obj_t)&set_type);
mp_map_add_qstr(&map_builtins, MP_QSTR_tuple, (mp_obj_t)&tuple_type);
mp_map_add_qstr(&map_builtins, MP_QSTR_type, (mp_obj_t)&mp_const_type);
-
- // built-in user functions; TODO covert all to &mp_builtin_xxx's
- mp_map_add_qstr(&map_builtins, MP_QSTR_abs, rt_make_function_1(mp_builtin_abs));
- mp_map_add_qstr(&map_builtins, MP_QSTR_all, rt_make_function_1(mp_builtin_all));
- mp_map_add_qstr(&map_builtins, MP_QSTR_any, rt_make_function_1(mp_builtin_any));
- mp_map_add_qstr(&map_builtins, MP_QSTR_callable, rt_make_function_1(mp_builtin_callable));
- mp_map_add_qstr(&map_builtins, MP_QSTR_chr, rt_make_function_1(mp_builtin_chr));
- mp_map_add_qstr(&map_builtins, MP_QSTR_divmod, rt_make_function_2(mp_builtin_divmod));
+ mp_map_add_qstr(&map_builtins, MP_QSTR_zip, (mp_obj_t)&zip_type);
+
+ // built-in user functions
+ mp_map_add_qstr(&map_builtins, MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_divmod, (mp_obj_t)&mp_builtin_divmod_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_eval, (mp_obj_t)&mp_builtin_eval_obj);
mp_map_add_qstr(&map_builtins, MP_QSTR_hash, (mp_obj_t)&mp_builtin_hash_obj);
mp_map_add_qstr(&map_builtins, MP_QSTR_isinstance, (mp_obj_t)&mp_builtin_isinstance_obj);
mp_map_add_qstr(&map_builtins, MP_QSTR_issubclass, (mp_obj_t)&mp_builtin_issubclass_obj);
mp_map_add_qstr(&map_builtins, MP_QSTR_iter, (mp_obj_t)&mp_builtin_iter_obj);
- mp_map_add_qstr(&map_builtins, MP_QSTR_len, rt_make_function_1(mp_builtin_len));
- mp_map_add_qstr(&map_builtins, MP_QSTR_max, rt_make_function_var(1, mp_builtin_max));
- mp_map_add_qstr(&map_builtins, MP_QSTR_min, rt_make_function_var(1, mp_builtin_min));
+ mp_map_add_qstr(&map_builtins, MP_QSTR_len, (mp_obj_t)&mp_builtin_len_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_max, (mp_obj_t)&mp_builtin_max_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_min, (mp_obj_t)&mp_builtin_min_obj);
mp_map_add_qstr(&map_builtins, MP_QSTR_next, (mp_obj_t)&mp_builtin_next_obj);
- mp_map_add_qstr(&map_builtins, MP_QSTR_ord, rt_make_function_1(mp_builtin_ord));
- mp_map_add_qstr(&map_builtins, MP_QSTR_pow, rt_make_function_var(2, mp_builtin_pow));
- mp_map_add_qstr(&map_builtins, MP_QSTR_print, rt_make_function_var(0, mp_builtin_print));
- mp_map_add_qstr(&map_builtins, MP_QSTR_range, rt_make_function_var(1, mp_builtin_range));
- mp_map_add_qstr(&map_builtins, MP_QSTR_sum, rt_make_function_var(1, mp_builtin_sum));
+ mp_map_add_qstr(&map_builtins, MP_QSTR_ord, (mp_obj_t)&mp_builtin_ord_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_pow, (mp_obj_t)&mp_builtin_pow_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_print, (mp_obj_t)&mp_builtin_print_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_range, (mp_obj_t)&mp_builtin_range_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_sorted, (mp_obj_t)&mp_builtin_sorted_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_sum, (mp_obj_t)&mp_builtin_sum_obj);
+ mp_map_add_qstr(&map_builtins, MP_QSTR_str, (mp_obj_t)&mp_builtin_str_obj);
next_unique_code_id = 1; // 0 indicates "no code"
unique_codes_alloc = 0;
@@ -267,10 +276,6 @@ void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_ar
#endif
}
-static bool fit_small_int(mp_small_int_t o) {
- return true;
-}
-
int rt_is_true(mp_obj_t arg) {
DEBUG_OP_printf("is true %p\n", arg);
if (MP_OBJ_IS_SMALL_INT(arg)) {
@@ -435,13 +440,10 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) {
case RT_UNARY_OP_INVERT: val = ~val; break;
default: assert(0); val = 0;
}
- if (fit_small_int(val)) {
+ if (MP_OBJ_FITS_SMALL_INT(val)) {
return MP_OBJ_NEW_SMALL_INT(val);
- } else {
- // TODO make a bignum
- assert(0);
- return mp_const_none;
}
+ return mp_obj_new_int(val);
} else { // will be an object (small ints are caught in previous if)
mp_obj_base_t *o = arg;
if (o->type->unary_op != NULL) {
@@ -467,6 +469,18 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
// then fail
// note that list does not implement + or +=, so that inplace_concat is reached first for +=
+ // deal with is, is not
+ if (op == RT_COMPARE_OP_IS) {
+ // TODO: may need to handle strings specially, CPython appears to
+ // assume all strings are interned (so "is" == "==" for strings)
+ return MP_BOOL(lhs == rhs);
+ }
+ if (op == RT_COMPARE_OP_IS_NOT) {
+ // TODO: may need to handle strings specially, CPython appears to
+ // assume all strings are interned (so "is" == "==" for strings)
+ return MP_BOOL(lhs != rhs);
+ }
+
// deal with == and != for all types
if (op == RT_COMPARE_OP_EQUAL || op == RT_COMPARE_OP_NOT_EQUAL) {
if (mp_obj_equal(lhs, rhs)) {
@@ -550,32 +564,67 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
default: assert(0);
}
- if (fit_small_int(lhs_val)) {
+ // TODO: We just should make mp_obj_new_int() inline and use that
+ if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
return MP_OBJ_NEW_SMALL_INT(lhs_val);
}
- // TODO: return long int
- assert(0);
+ return mp_obj_new_int(lhs_val);
} else if (MP_OBJ_IS_TYPE(rhs, &float_type)) {
return mp_obj_float_binary_op(op, lhs_val, rhs);
} else if (MP_OBJ_IS_TYPE(rhs, &complex_type)) {
return mp_obj_complex_binary_op(op, lhs_val, 0, rhs);
}
- } else {
- if (MP_OBJ_IS_OBJ(lhs)) {
- mp_obj_base_t *o = lhs;
+ }
+
+ /* deal with `in` and `not in`
+ *
+ * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch
+ * needs to go below
+ */
+ if (op == RT_COMPARE_OP_IN || op == RT_COMPARE_OP_NOT_IN) {
+ if (!MP_OBJ_IS_SMALL_INT(rhs)) {
+ mp_obj_base_t *o = rhs;
if (o->type->binary_op != NULL) {
- mp_obj_t result = o->type->binary_op(op, lhs, rhs);
- if (result != NULL) {
- return result;
+ mp_obj_t res = o->type->binary_op(op, rhs, lhs);
+ if (res != NULL) {
+ return res;
}
}
+ if (o->type->getiter != NULL) {
+ /* second attempt, walk the iterator */
+ mp_obj_t next = NULL;
+ mp_obj_t iter = rt_getiter(rhs);
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ if (mp_obj_equal(next, lhs)) {
+ return MP_BOOL(op == RT_COMPARE_OP_IN);
+ }
+ }
+ return MP_BOOL(op != RT_COMPARE_OP_IN);
+ }
+ }
+
+ nlr_jump(mp_obj_new_exception_msg_varg(
+ MP_QSTR_TypeError, "'%s' object is not iterable",
+ mp_obj_get_type_str(rhs)));
+ return mp_const_none;
+ }
+
+ if (MP_OBJ_IS_OBJ(lhs)) {
+ mp_obj_base_t *o = lhs;
+ if (o->type->binary_op != NULL) {
+ mp_obj_t result = o->type->binary_op(op, lhs, rhs);
+ if (result != NULL) {
+ return result;
+ }
}
+ // TODO implement dispatch for reverse binary ops
}
// TODO specify in error message what the operator is
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError,
"unsupported operand types for binary operator: '%s', '%s'",
mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs)));
+ return mp_const_none;
}
mp_obj_t rt_make_function_from_id(int unique_code_id) {
@@ -593,12 +642,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
fun = mp_obj_new_fun_bc(c->n_args, c->n_locals + c->n_stack, c->u_byte.code);
break;
case MP_CODE_NATIVE:
- switch (c->n_args) {
- case 0: fun = rt_make_function_0(c->u_native.fun); break;
- case 1: fun = rt_make_function_1((mp_fun_1_t)c->u_native.fun); break;
- case 2: fun = rt_make_function_2((mp_fun_2_t)c->u_native.fun); break;
- default: assert(0); fun = mp_const_none;
- }
+ fun = rt_make_function_n(c->n_args, c->u_native.fun);
break;
case MP_CODE_INLINE_ASM:
fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
diff --git a/py/runtime.h b/py/runtime.h
index ac53e14110..32cb47684f 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -12,10 +12,8 @@ void rt_store_global(qstr qstr, mp_obj_t obj);
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
mp_obj_t rt_make_function_from_id(int unique_code_id);
-mp_obj_t rt_make_function_0(mp_fun_0_t f);
-mp_obj_t rt_make_function_1(mp_fun_1_t f);
-mp_obj_t rt_make_function_2(mp_fun_2_t f);
-mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t f);
+mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments
+mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun);
mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive
mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple);
mp_obj_t rt_call_function_0(mp_obj_t fun);
diff --git a/py/stream.c b/py/stream.c
index f883efcd25..e70d365681 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -51,5 +51,91 @@ static mp_obj_t stream_write(mp_obj_t self_in, mp_obj_t arg) {
}
}
+// TODO: should be in mpconfig.h
+#define READ_SIZE 256
+static mp_obj_t stream_readall(mp_obj_t self_in) {
+ struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)self_in;
+ if (o->type->stream_p.read == NULL) {
+ // CPython: io.UnsupportedOperation, OSError subclass
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_OSError, "Operation not supported"));
+ }
+
+ int total_size = 0;
+ vstr_t *vstr = vstr_new_size(READ_SIZE);
+ char *buf = vstr_str(vstr);
+ char *p = buf;
+ int error;
+ int current_read = READ_SIZE;
+ while (true) {
+ machine_int_t out_sz = o->type->stream_p.read(self_in, p, current_read, &error);
+ if (out_sz == -1) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", error));
+ }
+ if (out_sz == 0) {
+ break;
+ }
+ total_size += out_sz;
+ if (out_sz < current_read) {
+ current_read -= out_sz;
+ p += out_sz;
+ } else {
+ current_read = READ_SIZE;
+ p = vstr_extend(vstr, current_read);
+ if (p == NULL) {
+ // TODO
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError/*MP_QSTR_RuntimeError*/, "Out of memory"));
+ }
+ }
+ }
+ vstr_set_size(vstr, total_size + 1); // TODO: for \0
+ buf[total_size] = 0;
+ return mp_obj_new_str(qstr_from_str_take(buf, total_size + 1));
+}
+
+// Unbuffered, inefficient implementation of readline() for raw I/O files.
+static mp_obj_t stream_unbuffered_readline(int 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.read == NULL) {
+ // CPython: io.UnsupportedOperation, OSError subclass
+ nlr_jump(mp_obj_new_exception_msg(MP_QSTR_OSError, "Operation not supported"));
+ }
+
+ machine_int_t max_size = -1;
+ if (n_args > 1) {
+ max_size = MP_OBJ_SMALL_INT_VALUE(args[1]);
+ }
+
+ vstr_t *vstr;
+ if (max_size != -1) {
+ vstr = vstr_new_size(max_size + 1); // TODO: \0
+ } else {
+ vstr = vstr_new();
+ }
+
+ int error;
+ while (max_size == -1 || max_size-- != 0) {
+ char *p = vstr_add_len(vstr, 1);
+ if (p == NULL) {
+ // TODO
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError/*MP_QSTR_RuntimeError*/, "Out of memory"));
+ }
+
+ machine_int_t out_sz = o->type->stream_p.read(o, p, 1, &error);
+ if (out_sz == -1) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", error));
+ }
+ if (out_sz == 0 || *p == '\n') {
+ break;
+ }
+ }
+ // TODO: \0
+ vstr_add_byte(vstr, 0);
+ vstr_shrink(vstr);
+ return mp_obj_new_str(qstr_from_str_take(vstr_str(vstr), vstr_len(vstr)));
+}
+
+
MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_read_obj, stream_read);
+MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_readall_obj, stream_readall);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj, 1, 2, stream_unbuffered_readline);
MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write_obj, stream_write);
diff --git a/py/stream.h b/py/stream.h
index 8a579b7621..58e8072549 100644
--- a/py/stream.h
+++ b/py/stream.h
@@ -1,2 +1,4 @@
extern const mp_obj_fun_native_t mp_stream_read_obj;
+extern const mp_obj_fun_native_t mp_stream_readall_obj;
+extern const mp_obj_fun_native_t mp_stream_unbuffered_readline_obj;
extern const mp_obj_fun_native_t mp_stream_write_obj;
diff --git a/py/strtonum.c b/py/strtonum.c
index 109ea1123b..02c1506683 100644
--- a/py/strtonum.c
+++ b/py/strtonum.c
@@ -10,7 +10,6 @@
#include "nlr.h"
#include "obj.h"
-
long strtonum(const char *restrict s, int base) {
int c, neg = 0;
const char *p = s;
@@ -33,6 +32,7 @@ long strtonum(const char *restrict s, int base) {
}
// find real radix base, and strip preced '0x', '0o' and '0b'
+ // TODO somehow merge with similar code in parse.c
if ((base == 0 || base == 16) && c == '0') {
c = *(p++);
if ((c | 32) == 'x') {
diff --git a/py/strtonum.h b/py/strtonum.h
deleted file mode 100644
index 03565cca14..0000000000
--- a/py/strtonum.h
+++ /dev/null
@@ -1 +0,0 @@
-long strtonum(const char *restrict s, int base);
diff --git a/py/vm.c b/py/vm.c
index baef6988c5..5c74b43caa 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -440,10 +440,17 @@ bool mp_execute_byte_code_2(const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **
case MP_BC_CALL_FUNCTION:
DECODE_UINT;
- assert((unum & 0xff00) == 0); // n_keyword
- unum &= 0xff; // n_positional
- sp += unum;
- *sp = rt_call_function_n(*sp, unum, sp - unum);
+ if ((unum & 0xff00) == 0) {
+ // no keywords
+ unum &= 0xff; // n_positional
+ sp += unum;
+ *sp = rt_call_function_n(*sp, unum, sp - unum);
+ } else {
+ // keywords
+ int argsize = (unum & 0xff) + ((unum >> 7) & 0x1fe);
+ sp += argsize;
+ *sp = rt_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp - argsize);
+ }
break;
case MP_BC_CALL_METHOD:
diff --git a/py/vstr.c b/py/vstr.c
index 80841b24ca..18e6d2d0a8 100644
--- a/py/vstr.c
+++ b/py/vstr.c
@@ -6,8 +6,8 @@
// returned value is always at least 1 greater than argument
#define ROUND_ALLOC(a) (((a) & ((~0) - 7)) + 8)
-void vstr_init(vstr_t *vstr) {
- vstr->alloc = 32;
+void vstr_init(vstr_t *vstr, int alloc) {
+ vstr->alloc = alloc;
vstr->len = 0;
vstr->buf = m_new(char, vstr->alloc);
if (vstr->buf == NULL) {
@@ -28,7 +28,16 @@ vstr_t *vstr_new(void) {
if (vstr == NULL) {
return NULL;
}
- vstr_init(vstr);
+ vstr_init(vstr, 32);
+ return vstr;
+}
+
+vstr_t *vstr_new_size(int alloc) {
+ vstr_t *vstr = m_new(vstr_t, 1);
+ if (vstr == NULL) {
+ return NULL;
+ }
+ vstr_init(vstr, alloc);
return vstr;
}
@@ -63,6 +72,36 @@ int vstr_len(vstr_t *vstr) {
return vstr->len;
}
+// Extend vstr strictly to by requested size, return pointer to newly added chunk
+char *vstr_extend(vstr_t *vstr, int size) {
+ char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size);
+ if (new_buf == NULL) {
+ vstr->had_error = true;
+ return NULL;
+ }
+ char *p = new_buf + vstr->alloc;
+ vstr->alloc += size;
+ vstr->buf = new_buf;
+ return p;
+}
+
+// Shrink vstr to be given size
+bool vstr_set_size(vstr_t *vstr, int size) {
+ char *new_buf = m_renew(char, vstr->buf, vstr->alloc, size);
+ if (new_buf == NULL) {
+ vstr->had_error = true;
+ return false;
+ }
+ vstr->buf = new_buf;
+ vstr->alloc = vstr->len = size;
+ return true;
+}
+
+// Shrink vstr allocation to its actual length
+bool vstr_shrink(vstr_t *vstr) {
+ return vstr_set_size(vstr, vstr->len);
+}
+
bool vstr_ensure_extra(vstr_t *vstr, int size) {
if (vstr->len + size + 1 > vstr->alloc) {
int new_alloc = ROUND_ALLOC((vstr->len + size + 1) * 2);