diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/builtin.c | 16 | ||||
-rw-r--r-- | py/builtin.h | 2 | ||||
-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/mpqstrraw.h | 5 | ||||
-rw-r--r-- | py/objfilter.c | 7 | ||||
-rw-r--r-- | py/objmap.c | 7 | ||||
-rw-r--r-- | py/parse.c | 20 | ||||
-rw-r--r-- | py/parse.h | 3 | ||||
-rw-r--r-- | py/py.mk | 1 | ||||
-rw-r--r-- | py/runtime.c | 2 | ||||
-rw-r--r-- | py/stream.c | 44 | ||||
-rw-r--r-- | py/stream.h | 1 |
17 files changed, 162 insertions, 40 deletions
diff --git a/py/builtin.c b/py/builtin.c index 8f93e843b5..837a9b2d09 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)")); } @@ -310,6 +308,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); + 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; @@ -324,6 +330,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) { @@ -343,4 +350,5 @@ 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); diff --git a/py/builtin.h b/py/builtin.h index 3401528a68..7d001341ae 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,5 +22,6 @@ 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); 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 diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h index f6b4444a70..356c911238 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) @@ -42,6 +43,7 @@ Q(complex) Q(dict) Q(divmod) Q(enumerate) +Q(eval) Q(filter) Q(float) Q(hash) @@ -59,6 +61,7 @@ Q(ord) Q(pow) Q(print) Q(range) +Q(repr) Q(set) Q(sorted) Q(sum) diff --git a/py/objfilter.c b/py/objfilter.c index 6696ffe32c..18225ac102 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -1,8 +1,10 @@ #include <stdlib.h> #include <assert.h> +#include "nlr.h" #include "misc.h" #include "mpconfig.h" +#include "mpqstr.h" #include "obj.h" #include "runtime.h" @@ -14,8 +16,11 @@ typedef struct _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 */ - mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t); + 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]); diff --git a/py/objmap.c b/py/objmap.c index 2e07d76b7b..365735283a 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -1,8 +1,10 @@ #include <stdlib.h> #include <assert.h> +#include "nlr.h" #include "misc.h" #include "mpconfig.h" +#include "mpqstr.h" #include "obj.h" #include "runtime.h" @@ -15,8 +17,11 @@ typedef struct _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 */ - mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1); + 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]; 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); @@ -97,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 04c098de3c..18a3269f49 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -125,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); @@ -137,6 +138,7 @@ 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); 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; |