diff options
-rw-r--r-- | py/builtin.c | 28 | ||||
-rw-r--r-- | py/builtin.h | 3 | ||||
-rw-r--r-- | py/builtineval.c | 50 | ||||
-rw-r--r-- | py/builtinimport.c | 9 | ||||
-rw-r--r-- | py/compile.c | 8 | ||||
-rw-r--r-- | py/grammar.h | 2 | ||||
-rw-r--r-- | py/lexer.c | 15 | ||||
-rw-r--r-- | py/lexer.h | 10 | ||||
-rw-r--r-- | py/misc.h | 2 | ||||
-rw-r--r-- | py/mpqstrraw.h | 7 | ||||
-rw-r--r-- | py/obj.h | 9 | ||||
-rw-r--r-- | py/objenumerate.c | 53 | ||||
-rw-r--r-- | py/objfilter.c | 58 | ||||
-rw-r--r-- | py/objmap.c | 60 | ||||
-rw-r--r-- | py/objstr.c | 9 | ||||
-rw-r--r-- | py/parse.c | 20 | ||||
-rw-r--r-- | py/parse.h | 3 | ||||
-rw-r--r-- | py/py.mk | 4 | ||||
-rw-r--r-- | py/runtime.c | 6 | ||||
-rw-r--r-- | py/stream.c | 44 | ||||
-rw-r--r-- | py/stream.h | 1 | ||||
-rw-r--r-- | stm/main.c | 31 | ||||
-rw-r--r-- | tests/basics/tests/enumerate.py | 6 | ||||
-rw-r--r-- | tests/basics/tests/eval1.py | 13 | ||||
-rw-r--r-- | tests/basics/tests/exception1.py | 2 | ||||
-rw-r--r-- | tests/basics/tests/filter.py | 2 | ||||
-rw-r--r-- | tests/basics/tests/map.py | 4 | ||||
-rw-r--r-- | unix-cpy/main.c | 17 | ||||
-rw-r--r-- | unix/file.c | 1 | ||||
-rw-r--r-- | unix/main.c | 10 |
30 files changed, 415 insertions, 72 deletions
diff --git a/py/builtin.c b/py/builtin.c index bc10f29d7e..04bb2681db 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -140,10 +140,8 @@ 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)")); } @@ -304,6 +302,14 @@ static mp_obj_t mp_builtin_range(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; @@ -318,6 +324,7 @@ static 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) { @@ -337,20 +344,13 @@ static mp_obj_t mp_builtin_sorted(mp_obj_t args, mp_map_t *kwargs) { return self; } + MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted); -mp_obj_t mp_builtin_str(mp_obj_t o) { +static mp_obj_t mp_builtin_str(mp_obj_t o_in) { vstr_t *vstr = vstr_new(); - mp_obj_print_helper(vstr_printf_wrapper, vstr, o, PRINT_STR); + 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); - -mp_obj_t mp_builtin_repr(mp_obj_t o) { - vstr_t *vstr = vstr_new(); - mp_obj_print_helper(vstr_printf_wrapper, vstr, o, 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); diff --git a/py/builtin.h b/py/builtin.h index 0716b952e5..f4038b47b4 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -8,6 +8,7 @@ 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); @@ -21,7 +22,7 @@ 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); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_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 33576e3f0e..2eca36fbc6 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -48,16 +48,19 @@ mp_obj_t mp_builtin___import__(int n_args, 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 b948f7aa47..b24e94a8dc 100644 --- a/py/compile.c +++ b/py/compile.c @@ -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/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 da8967b163..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) { @@ -684,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 428ff03c5b..ea928c77f8 100644 --- a/py/lexer.h +++ b/py/lexer.h @@ -124,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); @@ -134,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 @@ -81,8 +81,6 @@ void vstr_add_strn(vstr_t *vstr, const char *str, int len); //void vstr_add_le32(vstr_t *vstr, unsigned int v); void vstr_cut_tail(vstr_t *vstr, int len); void vstr_printf(vstr_t *vstr, const char *fmt, ...); -// TODO: do we need wrapper at all? -void vstr_printf_wrapper(void *env, const char *fmt, ...); #ifdef va_start void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap); diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h index 615c9da990..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) @@ -298,6 +298,15 @@ 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; uint mp_obj_dict_len(mp_obj_t self_in); 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/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/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/objstr.c b/py/objstr.c index 81fd952915..0621a8df75 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -258,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]; @@ -282,7 +275,7 @@ mp_obj_t str_format(int n_args, const mp_obj_t *args) { nlr_jump(mp_obj_new_exception_msg(MP_QSTR_IndexError, "tuple index out of range")); } // TODO: may be PRINT_REPR depending on formatting code - mp_obj_print_helper(vstr_printf_wrapper, vstr, args[arg_i], PRINT_STR); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_STR); arg_i++; } } else { diff --git a/py/parse.c b/py/parse.c index e2c9520736..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" @@ -265,7 +266,7 @@ 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) { +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 @@ -283,7 +284,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { 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); @@ -598,17 +599,20 @@ finished: return result; syntax_error: - // TODO these should raise a proper exception if (mp_lexer_is_kind(lex, MP_TOKEN_INDENT)) { - mp_lexer_show_error_pythonic(lex, "IndentationError: unexpected indent"); + *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 } 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); @@ -77,12 +77,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 \ @@ -94,6 +97,7 @@ PY_O_BASENAME = \ stream.o \ builtin.o \ builtinimport.o \ + builtineval.o \ vm.o \ showbc.o \ repl.o \ diff --git a/py/runtime.c b/py/runtime.c index 3f7595787b..e1e9e31cc7 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -105,11 +105,14 @@ 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); @@ -122,6 +125,7 @@ void rt_init(void) { 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); @@ -134,10 +138,10 @@ void rt_init(void) { 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); - mp_map_add_qstr(&map_builtins, MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj); next_unique_code_id = 1; // 0 indicates "no code" unique_codes_alloc = 0; diff --git a/py/stream.c b/py/stream.c index 48cd0bcd6c..e70d365681 100644 --- a/py/stream.c +++ b/py/stream.c @@ -92,6 +92,50 @@ static mp_obj_t stream_readall(mp_obj_t self_in) { 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 b1c3c72786..58e8072549 100644 --- a/py/stream.h +++ b/py/stream.h @@ -1,3 +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/stm/main.c b/stm/main.c index a27c4e52fb..d8649f5797 100644 --- a/stm/main.c +++ b/stm/main.c @@ -418,10 +418,18 @@ void do_repl(void) { } mp_lexer_t *lex = mp_lexer_new_from_str_len("<stdin>", vstr_str(&line), vstr_len(&line), 0); - mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT); - mp_lexer_free(lex); - - if (pn != MP_PARSE_NODE_NULL) { + qstr parse_exc_id; + const char *parse_exc_msg; + mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_exc_id, &parse_exc_msg); + + if (pn == MP_PARSE_NODE_NULL) { + // parse error + mp_lexer_show_error_pythonic_prefix(lex); + printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg); + mp_lexer_free(lex); + } else { + // parse okay + mp_lexer_free(lex); mp_obj_t module_fun = mp_compile(pn, true); if (module_fun != mp_const_none) { nlr_buf_t nlr; @@ -455,13 +463,20 @@ bool do_file(const char *filename) { return false; } - mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_lexer_free(lex); + 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); if (pn == MP_PARSE_NODE_NULL) { + // parse error + mp_lexer_show_error_pythonic_prefix(lex); + printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg); + mp_lexer_free(lex); return false; } + mp_lexer_free(lex); + mp_obj_t module_fun = mp_compile(pn, false); if (module_fun == mp_const_none) { return false; @@ -1073,7 +1088,9 @@ soft_reset: // nalloc=1740;6340;6836 -> 140;4600;496 bytes for lexer, parser, compiler printf("lex; al=%u\n", m_get_total_bytes_allocated()); sys_tick_delay_ms(1000); - 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) { printf("pars;al=%u\n", m_get_total_bytes_allocated()); diff --git a/tests/basics/tests/enumerate.py b/tests/basics/tests/enumerate.py new file mode 100644 index 0000000000..f2bdf4f326 --- /dev/null +++ b/tests/basics/tests/enumerate.py @@ -0,0 +1,6 @@ +print(list(enumerate([]))) +print(list(enumerate([1, 2, 3]))) +print(list(enumerate([1, 2, 3], 5))) +print(list(enumerate([1, 2, 3], -5))) +print(list(enumerate(range(10000)))) + diff --git a/tests/basics/tests/eval1.py b/tests/basics/tests/eval1.py new file mode 100644 index 0000000000..8b9d02e61b --- /dev/null +++ b/tests/basics/tests/eval1.py @@ -0,0 +1,13 @@ +# builtin eval + +eval('1 + 2') +eval('1 + 2\n') +eval('1 + 2\n\n#comment\n') + +x = 4 +eval('x') + +eval('lambda x: x + 10')(-5) + +y = 6 +eval('lambda: y * 2')() diff --git a/tests/basics/tests/exception1.py b/tests/basics/tests/exception1.py index 93d2cbfb92..71d5ad3041 100644 --- a/tests/basics/tests/exception1.py +++ b/tests/basics/tests/exception1.py @@ -5,5 +5,5 @@ print(repr(IndexError("foo"))) print(str(IndexError("foo"))) a = IndexError(1, "test", [100, 200]) -print(str(a)) print(repr(a)) +print(str(a)) diff --git a/tests/basics/tests/filter.py b/tests/basics/tests/filter.py new file mode 100644 index 0000000000..5883e3d00b --- /dev/null +++ b/tests/basics/tests/filter.py @@ -0,0 +1,2 @@ +print(list(filter(lambda x: x & 1, range(-3, 4)))) +print(list(filter(None, range(-3, 4)))) diff --git a/tests/basics/tests/map.py b/tests/basics/tests/map.py new file mode 100644 index 0000000000..62dca44ede --- /dev/null +++ b/tests/basics/tests/map.py @@ -0,0 +1,4 @@ +print(list(map(lambda x: x & 1, range(-3, 4)))) +print(list(map(abs, range(-3, 4)))) +print(list(map(set, [[i] for i in range(-3, 4)]))) +print(list(map(pow, range(4), range(4)))) diff --git a/unix-cpy/main.c b/unix-cpy/main.c index ea85e32757..7d56ceaf34 100644 --- a/unix-cpy/main.c +++ b/unix-cpy/main.c @@ -27,16 +27,29 @@ void do_file(const char *file) { mp_lexer_free(lex); } else { - // compile + // parse + 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); + + if (pn == MP_PARSE_NODE_NULL) { + // parse error + mp_lexer_show_error_pythonic_prefix(lex); + printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg); + mp_lexer_free(lex); + return; + } - mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_lexer_free(lex); if (pn != MP_PARSE_NODE_NULL) { //printf("----------------\n"); //parse_node_show(pn, 0); //printf("----------------\n"); + + // compile mp_obj_t module_fun = mp_compile(pn, false); + //printf("----------------\n"); if (module_fun == mp_const_none) { diff --git a/unix/file.c b/unix/file.c index eef3378d80..e15e82775c 100644 --- a/unix/file.c +++ b/unix/file.c @@ -91,6 +91,7 @@ static mp_obj_t fdfile_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *ar static const mp_method_t rawfile_type_methods[] = { { "read", &mp_stream_read_obj }, { "readall", &mp_stream_readall_obj }, + { "readline", &mp_stream_unbuffered_readline_obj}, { "write", &mp_stream_write_obj }, { "close", &fdfile_close_obj }, { NULL, NULL }, diff --git a/unix/main.c b/unix/main.c index e96ee28464..d89f39da70 100644 --- a/unix/main.c +++ b/unix/main.c @@ -37,14 +37,20 @@ static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind return; } - mp_parse_node_t pn = mp_parse(lex, input_kind); - mp_lexer_free(lex); + qstr parse_exc_id; + const char *parse_exc_msg; + mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_exc_id, &parse_exc_msg); if (pn == MP_PARSE_NODE_NULL) { // parse error + mp_lexer_show_error_pythonic_prefix(lex); + printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg); + mp_lexer_free(lex); return; } + mp_lexer_free(lex); + //printf("----------------\n"); //parse_node_show(pn, 0); //printf("----------------\n"); |