summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/bc.c1
-rw-r--r--py/builtin.h6
-rw-r--r--py/builtinimport.c21
-rw-r--r--py/compile.c238
-rw-r--r--py/emitglue.c30
-rw-r--r--py/emitglue.h26
-rw-r--r--py/emitnative.c2
-rw-r--r--py/frozenmod.c65
-rw-r--r--py/frozenmod.h8
-rw-r--r--py/grammar.h119
-rw-r--r--py/lexer.c4
-rw-r--r--py/lexer.h4
-rw-r--r--py/makeqstrdata.py72
-rw-r--r--py/makeqstrdefs.py109
-rw-r--r--py/map.c29
-rw-r--r--py/mkrules.mk30
-rw-r--r--py/modbuiltins.c4
-rw-r--r--py/modcollections.c4
-rw-r--r--py/modio.c4
-rw-r--r--py/mpconfig.h29
-rw-r--r--py/obj.h7
-rw-r--r--py/objexcept.c3
-rw-r--r--py/objgenerator.c1
-rw-r--r--py/objmodule.c10
-rw-r--r--py/objstr.c2
-rw-r--r--py/parse.c94
-rw-r--r--py/py.mk19
-rw-r--r--py/qstr.c19
-rw-r--r--py/qstr.h4
-rw-r--r--py/qstrdefs.h721
-rw-r--r--py/repl.c3
-rw-r--r--py/runtime.c14
-rw-r--r--py/runtime.h3
-rw-r--r--py/runtime_utils.c50
-rw-r--r--py/vm.c3
35 files changed, 813 insertions, 945 deletions
diff --git a/py/bc.c b/py/bc.c
index 750ca2aed8..5cdaa4770d 100644
--- a/py/bc.c
+++ b/py/bc.c
@@ -171,6 +171,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_fun_bc_t *self, size_
const mp_obj_t *arg_names = (const mp_obj_t*)code_state->const_table;
for (size_t i = 0; i < n_kw; i++) {
+ // the keys in kwargs are expected to be qstr objects
mp_obj_t wanted_arg_name = kwargs[2 * i];
for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
if (wanted_arg_name == arg_names[j]) {
diff --git a/py/builtin.h b/py/builtin.h
index e3e68e1519..9d6e424091 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -71,6 +71,10 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_round_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj);
+// Defined by a port, but declared here for simplicity
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_help_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_input_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_open_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_namedtuple_obj);
@@ -106,6 +110,8 @@ extern const mp_obj_module_t mp_module_ussl;
extern const mp_obj_module_t mp_module_machine;
extern const mp_obj_module_t mp_module_lwip;
extern const mp_obj_module_t mp_module_websocket;
+extern const mp_obj_module_t mp_module_webrepl;
+extern const mp_obj_module_t mp_module_framebuf;
// extmod functions
MP_DECLARE_CONST_FUN_OBJ(pyb_mount_obj);
diff --git a/py/builtinimport.c b/py/builtinimport.c
index ec79357cb7..0e4dce6430 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -144,7 +144,7 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char
}
#endif
-#if MICROPY_PERSISTENT_CODE_LOAD
+#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY
STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) {
#if MICROPY_PY___FILE__
// TODO
@@ -182,8 +182,9 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) {
#endif
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
- // create the lexer
+ #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER
char *file_str = vstr_null_terminated_str(file);
+ #endif
#if MICROPY_PERSISTENT_CODE_LOAD
if (file_str[file->len - 3] == 'm') {
@@ -340,8 +341,9 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
DEBUG_printf("Module not yet loaded\n");
#if MICROPY_MODULE_FROZEN
- mp_lexer_t *lex = mp_find_frozen_module(mod_str, mod_len);
- if (lex != NULL) {
+ void *frozen_data;
+ int frozen_type = mp_find_frozen_module(mod_str, mod_len, &frozen_data);
+ if (frozen_type != MP_FROZEN_NONE) {
module_obj = mp_obj_new_module(module_name_qstr);
// if args[3] (fromtuple) has magic value False, set up
// this module for command-line "-m" option (set module's
@@ -351,7 +353,16 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
}
- do_load_from_lexer(module_obj, lex, mod_str);
+ #if MICROPY_MODULE_FROZEN_STR
+ if (frozen_type == MP_FROZEN_STR) {
+ do_load_from_lexer(module_obj, frozen_data, mod_str);
+ }
+ #endif
+ #if MICROPY_MODULE_FROZEN_MPY
+ if (frozen_type == MP_FROZEN_MPY) {
+ do_execute_raw_code(module_obj, frozen_data);
+ }
+ #endif
return module_obj;
}
#endif
diff --git a/py/compile.c b/py/compile.c
index ae91455e0e..d40d8a1ff5 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -318,14 +318,14 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
-STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
+STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
if (assign_kind != ASSIGN_AUG_STORE) {
compile_node(comp, pns->nodes[0]);
}
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
- if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) {
+ if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
if (assign_kind != ASSIGN_AUG_STORE) {
for (int i = 0; i < n - 1; i++) {
@@ -366,10 +366,6 @@ STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign
goto cannot_assign;
}
- if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
- goto cannot_assign;
- }
-
return;
cannot_assign:
@@ -440,9 +436,9 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
// pn must be a struct
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
- case PN_power:
+ case PN_atom_expr_normal:
// lhs is an index or attribute
- c_assign_power(comp, pns, assign_kind);
+ c_assign_atom_expr(comp, pns, assign_kind);
break;
case PN_testlist_star_expr:
@@ -818,11 +814,19 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
- // compile the body (funcdef or classdef) and get its name
+ // compile the body (funcdef, async funcdef or classdef) and get its name
mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1];
qstr body_name = 0;
if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
body_name = compile_funcdef_helper(comp, pns_body, emit_options);
+ #if MICROPY_PY_ASYNC_AWAIT
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) {
+ assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0]));
+ mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0];
+ body_name = compile_funcdef_helper(comp, pns0, emit_options);
+ scope_t *fscope = (scope_t*)pns0->nodes[4];
+ fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
+ #endif
} else {
assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be
body_name = compile_classdef_helper(comp, pns_body, emit_options);
@@ -846,14 +850,14 @@ STATIC void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_ID(pn)) {
compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn));
- } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) {
+ } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
- compile_node(comp, pns->nodes[0]); // base of the power node
+ compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
- if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) {
+ if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
for (int i = 0; i < n - 1; i++) {
compile_node(comp, pns1->nodes[i]);
@@ -874,9 +878,6 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
goto cannot_delete;
}
- if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
- goto cannot_delete;
- }
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {
pn = ((mp_parse_node_struct_t*)pn)->nodes[0];
if (MP_PARSE_NODE_IS_NULL(pn)) {
@@ -1397,12 +1398,11 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// this bit optimises: for <x> in range(...), turning it into an explicitly incremented variable
// this is actually slower, but uses no heap memory
// for viper it will be much, much faster
- if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_power)) {
+ if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_atom_expr_normal)) {
mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1];
- if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])
+ if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])
&& MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range
- && MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren)
- && MP_PARSE_NODE_IS_NULL(pns_it->nodes[2])) {
+ && MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren)) {
mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t*)pns_it->nodes[1])->nodes[0];
mp_parse_node_t *args;
int n_args = mp_parse_node_extract_list(&pn_range_args, PN_arglist, &args);
@@ -1661,6 +1661,177 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_with_stmt_helper(comp, n, nodes, pns->nodes[1]);
}
+STATIC void compile_yield_from(compiler_t *comp) {
+ EMIT(get_iter);
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
+ EMIT(yield_from);
+}
+
+#if MICROPY_PY_ASYNC_AWAIT
+STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
+ EMIT_ARG(load_method, method);
+ EMIT_ARG(call_method, 0, 0, 0);
+ compile_yield_from(comp);
+}
+
+STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ // comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
+
+ qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
+ uint while_else_label = comp_next_label(comp);
+ uint try_exception_label = comp_next_label(comp);
+ uint try_else_label = comp_next_label(comp);
+ uint try_finally_label = comp_next_label(comp);
+
+ compile_node(comp, pns->nodes[1]); // iterator
+ compile_await_object_method(comp, MP_QSTR___aiter__);
+ compile_store_id(comp, context);
+
+ START_BREAK_CONTINUE_BLOCK
+
+ EMIT_ARG(label_assign, continue_label);
+
+ EMIT_ARG(setup_except, try_exception_label);
+ compile_increase_except_level(comp);
+
+ compile_load_id(comp, context);
+ compile_await_object_method(comp, MP_QSTR___anext__);
+ c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable
+ EMIT(pop_block);
+ EMIT_ARG(jump, try_else_label);
+
+ EMIT_ARG(label_assign, try_exception_label);
+ EMIT(start_except_handler);
+ EMIT(dup_top);
+ EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration);
+ EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);
+ EMIT_ARG(pop_jump_if, false, try_finally_label);
+ EMIT(pop_top);
+ EMIT(pop_top);
+ EMIT(pop_top);
+ EMIT(pop_except);
+ EMIT_ARG(jump, while_else_label);
+
+ EMIT_ARG(label_assign, try_finally_label);
+ EMIT_ARG(adjust_stack_size, 3);
+ compile_decrease_except_level(comp);
+ EMIT(end_finally);
+ EMIT(end_except_handler);
+
+ EMIT_ARG(label_assign, try_else_label);
+ compile_node(comp, pns->nodes[2]); // body
+
+ EMIT_ARG(jump, continue_label);
+ // break/continue apply to outer loop (if any) in the else block
+ END_BREAK_CONTINUE_BLOCK
+
+ EMIT_ARG(label_assign, while_else_label);
+ compile_node(comp, pns->nodes[3]); // else
+
+ EMIT_ARG(label_assign, break_label);
+}
+
+STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
+ if (n == 0) {
+ // no more pre-bits, compile the body of the with
+ compile_node(comp, body);
+ } else {
+ uint try_exception_label = comp_next_label(comp);
+ uint no_reraise_label = comp_next_label(comp);
+ uint try_else_label = comp_next_label(comp);
+ uint end_label = comp_next_label(comp);
+ qstr context;
+
+ if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) {
+ // this pre-bit is of the form "a as b"
+ mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0];
+ compile_node(comp, pns->nodes[0]);
+ context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
+ compile_store_id(comp, context);
+ compile_load_id(comp, context);
+ compile_await_object_method(comp, MP_QSTR___aenter__);
+ c_assign(comp, pns->nodes[1], ASSIGN_STORE);
+ } else {
+ // this pre-bit is just an expression
+ compile_node(comp, nodes[0]);
+ context = MP_PARSE_NODE_LEAF_ARG(nodes[0]);
+ compile_store_id(comp, context);
+ compile_load_id(comp, context);
+ compile_await_object_method(comp, MP_QSTR___aenter__);
+ EMIT(pop_top);
+ }
+
+ compile_load_id(comp, context);
+ EMIT_ARG(load_method, MP_QSTR___aexit__);
+
+ EMIT_ARG(setup_except, try_exception_label);
+ compile_increase_except_level(comp);
+ // compile additional pre-bits and the body
+ compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body);
+ // finish this with block
+ EMIT(pop_block);
+ EMIT_ARG(jump, try_else_label); // jump over exception handler
+
+ EMIT_ARG(label_assign, try_exception_label); // start of exception handler
+ EMIT(start_except_handler);
+ EMIT(rot_three);
+ EMIT(rot_two);
+ EMIT_ARG(call_method, 3, 0, 0);
+ compile_yield_from(comp);
+ EMIT_ARG(pop_jump_if, true, no_reraise_label);
+ EMIT_ARG(raise_varargs, 0);
+
+ EMIT_ARG(label_assign, no_reraise_label);
+ EMIT(pop_except);
+ EMIT_ARG(jump, end_label);
+
+ EMIT_ARG(adjust_stack_size, 5);
+ compile_decrease_except_level(comp);
+ EMIT(end_finally);
+ EMIT(end_except_handler);
+
+ EMIT_ARG(label_assign, try_else_label); // start of try-else handler
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
+ EMIT(dup_top);
+ EMIT(dup_top);
+ EMIT_ARG(call_method, 3, 0, 0);
+ compile_yield_from(comp);
+ EMIT(pop_top);
+
+ EMIT_ARG(label_assign, end_label);
+
+ }
+}
+
+STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)
+ mp_parse_node_t *nodes;
+ int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);
+ assert(n > 0);
+
+ // compile in a nested fashion
+ compile_async_with_stmt_helper(comp, n, nodes, pns->nodes[1]);
+}
+
+STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[0]));
+ mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0];
+ if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_funcdef) {
+ // async def
+ compile_funcdef(comp, pns0);
+ scope_t *fscope = (scope_t*)pns0->nodes[4];
+ fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
+ // async for
+ compile_async_for_stmt(comp, pns0);
+ } else {
+ // async with
+ assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt);
+ compile_async_with_stmt(comp, pns0);
+ }
+}
+#endif
+
STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) {
@@ -1967,15 +2138,16 @@ STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
-STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
+STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) {
// this is to handle special super() call
comp->func_arg_is_super = MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super;
compile_generic_all_nodes(comp, pns);
+}
- if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
- EMIT_ARG(binary_op, MP_BINARY_OP_POWER);
- }
+STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power
+ EMIT_ARG(binary_op, MP_BINARY_OP_POWER);
}
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {
@@ -2076,7 +2248,7 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
}
}
-STATIC void compile_power_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) {
+STATIC void compile_atom_expr_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) {
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (int i = 0; i < num_nodes; i++) {
if (i + 1 < num_nodes && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[i], PN_trailer_period) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[i + 1], PN_trailer_paren)) {
@@ -2431,15 +2603,24 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) {
pns = (mp_parse_node_struct_t*)pns->nodes[0];
compile_node(comp, pns->nodes[0]);
- EMIT(get_iter);
- EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
- EMIT(yield_from);
+ compile_yield_from(comp);
} else {
compile_node(comp, pns->nodes[0]);
EMIT(yield_value);
}
}
+#if MICROPY_PY_ASYNC_AWAIT
+STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) {
+ compile_syntax_error(comp, (mp_parse_node_t)pns, "'await' outside function");
+ return;
+ }
+ compile_atom_expr_normal(comp, pns);
+ compile_yield_from(comp);
+}
+#endif
+
STATIC void compile_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
// only create and load the actual str object on the last pass
if (comp->pass != MP_PASS_EMIT) {
@@ -2995,7 +3176,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
goto not_an_instruction;
}
pns2 = (mp_parse_node_struct_t*)pns2->nodes[0];
- if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_power) {
+ if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_atom_expr_normal) {
goto not_an_instruction;
}
if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) {
@@ -3004,7 +3185,6 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns2->nodes[1], PN_trailer_paren)) {
goto not_an_instruction;
}
- assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[2]));
// parse node looks like an instruction
// get instruction name and args
diff --git a/py/emitglue.c b/py/emitglue.c
index e327d9d0cb..b710371177 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -49,28 +49,6 @@
mp_uint_t mp_verbose_flag = 0;
#endif
-struct _mp_raw_code_t {
- mp_raw_code_kind_t kind : 3;
- mp_uint_t scope_flags : 7;
- mp_uint_t n_pos_args : 11;
- union {
- struct {
- const byte *bytecode;
- const mp_uint_t *const_table;
- #if MICROPY_PERSISTENT_CODE_SAVE
- mp_uint_t bc_len;
- uint16_t n_obj;
- uint16_t n_raw_code;
- #endif
- } u_byte;
- struct {
- void *fun_data;
- const mp_uint_t *const_table;
- mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
- } u_native;
- } data;
-};
-
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
rc->kind = MP_CODE_RESERVED;
@@ -136,7 +114,7 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
}
#endif
-mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
+mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
assert(rc != NULL);
@@ -180,7 +158,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
return fun;
}
-mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
+mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
// make function object
mp_obj_t ffun;
@@ -195,7 +173,7 @@ mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_ove
return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2));
}
-#if MICROPY_PERSISTENT_CODE
+#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
#include "py/smallint.h"
@@ -252,7 +230,7 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_
}
}
-#endif // MICROPY_PERSISTENT_CODE
+#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
#if MICROPY_PERSISTENT_CODE_LOAD
diff --git a/py/emitglue.h b/py/emitglue.h
index b31e8dbb22..f5618577d5 100644
--- a/py/emitglue.h
+++ b/py/emitglue.h
@@ -39,7 +39,27 @@ typedef enum {
MP_CODE_NATIVE_ASM,
} mp_raw_code_kind_t;
-typedef struct _mp_raw_code_t mp_raw_code_t;
+typedef struct _mp_raw_code_t {
+ mp_raw_code_kind_t kind : 3;
+ mp_uint_t scope_flags : 7;
+ mp_uint_t n_pos_args : 11;
+ union {
+ struct {
+ const byte *bytecode;
+ const mp_uint_t *const_table;
+ #if MICROPY_PERSISTENT_CODE_SAVE
+ mp_uint_t bc_len;
+ uint16_t n_obj;
+ uint16_t n_raw_code;
+ #endif
+ } u_byte;
+ struct {
+ void *fun_data;
+ const mp_uint_t *const_table;
+ mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
+ } u_native;
+ } data;
+} mp_raw_code_t;
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
@@ -51,8 +71,8 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t
mp_uint_t scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig);
-mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
-mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);
+mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
+mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);
#if MICROPY_PERSISTENT_CODE_LOAD
typedef struct _mp_reader_t {
diff --git a/py/emitnative.c b/py/emitnative.c
index a03ab36ed5..9adaabc11c 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -1208,7 +1208,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
break;
case VTYPE_INT:
case VTYPE_UINT:
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->data.u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
+ ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), emit->stack_start + emit->stack_size - 1 - i, reg_dest);
si->vtype = VTYPE_PYOBJ;
break;
default:
diff --git a/py/frozenmod.c b/py/frozenmod.c
index 6b76bf662b..18beb0f8e4 100644
--- a/py/frozenmod.c
+++ b/py/frozenmod.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2015 Paul Sokolovsky
+ * Copyright (c) 2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,7 +31,7 @@
#include "py/lexer.h"
#include "py/frozenmod.h"
-#if MICROPY_MODULE_FROZEN
+#if MICROPY_MODULE_FROZEN_STR
#ifndef MICROPY_MODULE_FROZEN_LEXER
#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str_len
@@ -38,24 +39,68 @@
mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
#endif
-extern const char mp_frozen_names[];
-extern const uint32_t mp_frozen_sizes[];
-extern const char mp_frozen_content[];
+extern const char mp_frozen_str_names[];
+extern const uint32_t mp_frozen_str_sizes[];
+extern const char mp_frozen_str_content[];
-mp_lexer_t *mp_find_frozen_module(const char *str, int len) {
- const char *name = mp_frozen_names;
+STATIC mp_lexer_t *mp_find_frozen_str(const char *str, size_t len) {
+ const char *name = mp_frozen_str_names;
size_t offset = 0;
for (int i = 0; *name != 0; i++) {
- int l = strlen(name);
+ size_t l = strlen(name);
if (l == len && !memcmp(str, name, l)) {
- mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(MP_QSTR_, mp_frozen_content + offset, mp_frozen_sizes[i], 0);
+ qstr source = qstr_from_strn(name, l);
+ mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, mp_frozen_str_content + offset, mp_frozen_str_sizes[i], 0);
return lex;
}
name += l + 1;
- offset += mp_frozen_sizes[i] + 1;
+ offset += mp_frozen_str_sizes[i] + 1;
+ }
+ return NULL;
+}
+
+#endif
+
+#if MICROPY_MODULE_FROZEN_MPY
+
+#include "py/emitglue.h"
+
+extern const char mp_frozen_mpy_names[];
+extern const mp_raw_code_t *const mp_frozen_mpy_content[];
+
+STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) {
+ const char *name = mp_frozen_mpy_names;
+ for (size_t i = 0; *name != 0; i++) {
+ size_t l = strlen(name);
+ if (l == len && !memcmp(str, name, l)) {
+ return mp_frozen_mpy_content[i];
+ }
+ name += l + 1;
}
return NULL;
}
-#endif // MICROPY_MODULE_FROZEN
+#endif
+
+#if MICROPY_MODULE_FROZEN
+
+int mp_find_frozen_module(const char *str, size_t len, void **data) {
+ #if MICROPY_MODULE_FROZEN_STR
+ mp_lexer_t *lex = mp_find_frozen_str(str, len);
+ if (lex != NULL) {
+ *data = lex;
+ return MP_FROZEN_STR;
+ }
+ #endif
+ #if MICROPY_MODULE_FROZEN_MPY
+ const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len);
+ if (rc != NULL) {
+ *data = (void*)rc;
+ return MP_FROZEN_MPY;
+ }
+ #endif
+ return MP_FROZEN_NONE;
+}
+
+#endif
diff --git a/py/frozenmod.h b/py/frozenmod.h
index 67caced14d..a1638d2293 100644
--- a/py/frozenmod.h
+++ b/py/frozenmod.h
@@ -24,4 +24,10 @@
* THE SOFTWARE.
*/
-mp_lexer_t *mp_find_frozen_module(const char *str, int len);
+enum {
+ MP_FROZEN_NONE,
+ MP_FROZEN_STR,
+ MP_FROZEN_MPY,
+};
+
+int mp_find_frozen_module(const char *str, size_t len, void **data);
diff --git a/py/grammar.h b/py/grammar.h
index 89a5a06537..dd21d193a1 100644
--- a/py/grammar.h
+++ b/py/grammar.h
@@ -38,16 +38,17 @@
// eval_input: testlist NEWLINE* ENDMARKER
DEF_RULE(single_input, nc, or(3), tok(NEWLINE), rule(simple_stmt), rule(compound_stmt))
-DEF_RULE(file_input, c(generic_all_nodes), and(1), opt_rule(file_input_2))
+DEF_RULE(file_input, c(generic_all_nodes), and_ident(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, nc, and_ident(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+
-// decorated: decorators (classdef | funcdef)
+// decorated: decorators (classdef | funcdef | async_funcdef)
// funcdef: 'def' NAME parameters ['->' test] ':' suite
+// async_funcdef: 'async' funcdef
// parameters: '(' [typedargslist] ')'
// typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef
// tfpdef: NAME [':' test]
@@ -56,27 +57,32 @@ DEF_RULE(eval_input_2, nc, and(1), tok(NEWLINE))
DEF_RULE(decorator, nc, and(4), tok(DEL_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE))
DEF_RULE(decorators, nc, one_or_more, rule(decorator))
-DEF_RULE(decorated, c(decorated), and(2), rule(decorators), rule(decorated_body))
+DEF_RULE(decorated, c(decorated), and_ident(2), rule(decorators), rule(decorated_body))
+#if MICROPY_PY_ASYNC_AWAIT
+DEF_RULE(decorated_body, nc, or(3), rule(classdef), rule(funcdef), rule(async_funcdef))
+DEF_RULE(async_funcdef, nc, and(2), tok(KW_ASYNC), rule(funcdef))
+#else
DEF_RULE(decorated_body, nc, or(2), rule(classdef), rule(funcdef))
-DEF_RULE(funcdef, c(funcdef), blank | and(8), tok(KW_DEF), tok(NAME), tok(DEL_PAREN_OPEN), opt_rule(typedargslist), tok(DEL_PAREN_CLOSE), opt_rule(funcdefrettype), tok(DEL_COLON), rule(suite))
-DEF_RULE(funcdefrettype, nc, ident | and(2), tok(DEL_MINUS_MORE), rule(test))
+#endif
+DEF_RULE(funcdef, c(funcdef), and_blank(8), tok(KW_DEF), tok(NAME), tok(DEL_PAREN_OPEN), opt_rule(typedargslist), tok(DEL_PAREN_CLOSE), opt_rule(funcdefrettype), tok(DEL_COLON), rule(suite))
+DEF_RULE(funcdefrettype, nc, and_ident(2), tok(DEL_MINUS_MORE), rule(test))
// note: typedargslist lets through more than is allowed, compiler does further checks
DEF_RULE(typedargslist, nc, list_with_end, rule(typedargslist_item), tok(DEL_COMMA))
DEF_RULE(typedargslist_item, nc, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star))
-DEF_RULE(typedargslist_name, nc, ident | and(3), tok(NAME), opt_rule(typedargslist_colon), opt_rule(typedargslist_equal))
+DEF_RULE(typedargslist_name, nc, and_ident(3), tok(NAME), opt_rule(typedargslist_colon), opt_rule(typedargslist_equal))
DEF_RULE(typedargslist_star, nc, and(2), tok(OP_STAR), opt_rule(tfpdef))
DEF_RULE(typedargslist_dbl_star, nc, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(typedargslist_colon))
-DEF_RULE(typedargslist_colon, nc, ident | and(2), tok(DEL_COLON), rule(test))
-DEF_RULE(typedargslist_equal, nc, ident | and(2), tok(DEL_EQUAL), rule(test))
+DEF_RULE(typedargslist_colon, nc, and_ident(2), tok(DEL_COLON), rule(test))
+DEF_RULE(typedargslist_equal, nc, and_ident(2), tok(DEL_EQUAL), rule(test))
DEF_RULE(tfpdef, nc, and(2), tok(NAME), opt_rule(typedargslist_colon))
// note: varargslist lets through more than is allowed, compiler does further checks
DEF_RULE(varargslist, nc, list_with_end, rule(varargslist_item), tok(DEL_COMMA))
DEF_RULE(varargslist_item, nc, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star))
-DEF_RULE(varargslist_name, nc, ident | and(2), tok(NAME), opt_rule(varargslist_equal))
+DEF_RULE(varargslist_name, nc, and_ident(2), tok(NAME), opt_rule(varargslist_equal))
DEF_RULE(varargslist_star, nc, and(2), tok(OP_STAR), opt_rule(vfpdef))
DEF_RULE(varargslist_dbl_star, nc, and(2), tok(OP_DBL_STAR), tok(NAME))
-DEF_RULE(varargslist_equal, nc, ident | and(2), tok(DEL_EQUAL), rule(test))
-DEF_RULE(vfpdef, nc, ident | and(1), tok(NAME))
+DEF_RULE(varargslist_equal, nc, and_ident(2), tok(DEL_EQUAL), rule(test))
+DEF_RULE(vfpdef, nc, and_ident(1), tok(NAME))
// stmt: compound_stmt | simple_stmt
@@ -84,7 +90,7 @@ DEF_RULE(stmt, nc, or(2), rule(compound_stmt), rule(simple_stmt))
// simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
-DEF_RULE(simple_stmt, nc, and(2), rule(simple_stmt_2), tok(NEWLINE))
+DEF_RULE(simple_stmt, nc, and_ident(2), rule(simple_stmt_2), tok(NEWLINE))
DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), tok(DEL_SEMICOLON))
// small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt
@@ -96,9 +102,9 @@ DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), t
DEF_RULE(small_stmt, nc, or(8), rule(del_stmt), rule(pass_stmt), rule(flow_stmt), rule(import_stmt), rule(global_stmt), rule(nonlocal_stmt), rule(assert_stmt), rule(expr_stmt))
DEF_RULE(expr_stmt, c(expr_stmt), and(2), rule(testlist_star_expr), opt_rule(expr_stmt_2))
DEF_RULE(expr_stmt_2, nc, or(2), rule(expr_stmt_augassign), rule(expr_stmt_assign_list))
-DEF_RULE(expr_stmt_augassign, nc, and(2), rule(augassign), rule(expr_stmt_6))
+DEF_RULE(expr_stmt_augassign, nc, and_ident(2), rule(augassign), rule(expr_stmt_6))
DEF_RULE(expr_stmt_assign_list, nc, one_or_more, rule(expr_stmt_assign))
-DEF_RULE(expr_stmt_assign, nc, ident | and(2), tok(DEL_EQUAL), rule(expr_stmt_6))
+DEF_RULE(expr_stmt_assign, nc, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6))
DEF_RULE(expr_stmt_6, nc, or(2), rule(yield_expr), rule(testlist_star_expr))
DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA))
DEF_RULE(testlist_star_expr_2, nc, or(2), rule(star_expr), rule(test))
@@ -121,8 +127,8 @@ DEF_RULE(continue_stmt, c(continue_stmt), and(1), tok(KW_CONTINUE))
DEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist))
DEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr))
DEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg))
-DEF_RULE(raise_stmt_arg, nc, and(2), rule(test), opt_rule(raise_stmt_from))
-DEF_RULE(raise_stmt_from, nc, ident | and(2), tok(KW_FROM), rule(test))
+DEF_RULE(raise_stmt_arg, nc, and_ident(2), rule(test), opt_rule(raise_stmt_from))
+DEF_RULE(raise_stmt_from, nc, and_ident(2), tok(KW_FROM), rule(test))
// import_stmt: import_name | import_from
// import_name: 'import' dotted_as_names
@@ -140,14 +146,14 @@ DEF_RULE(import_stmt, nc, or(2), rule(import_name), rule(import_from))
DEF_RULE(import_name, c(import_name), and(2), tok(KW_IMPORT), rule(dotted_as_names))
DEF_RULE(import_from, c(import_from), and(4), tok(KW_FROM), rule(import_from_2), tok(KW_IMPORT), rule(import_from_3))
DEF_RULE(import_from_2, nc, or(2), rule(dotted_name), rule(import_from_2b))
-DEF_RULE(import_from_2b, nc, and(2), rule(one_or_more_period_or_ellipsis), opt_rule(dotted_name))
+DEF_RULE(import_from_2b, nc, and_ident(2), rule(one_or_more_period_or_ellipsis), opt_rule(dotted_name))
DEF_RULE(import_from_3, nc, or(3), tok(OP_STAR), rule(import_as_names_paren), rule(import_as_names))
-DEF_RULE(import_as_names_paren, nc, ident | and(3), tok(DEL_PAREN_OPEN), rule(import_as_names), tok(DEL_PAREN_CLOSE))
+DEF_RULE(import_as_names_paren, nc, and_ident(3), tok(DEL_PAREN_OPEN), rule(import_as_names), tok(DEL_PAREN_CLOSE))
DEF_RULE(one_or_more_period_or_ellipsis, nc, one_or_more, rule(period_or_ellipsis))
DEF_RULE(period_or_ellipsis, nc, or(2), tok(DEL_PERIOD), tok(ELLIPSIS))
DEF_RULE(import_as_name, nc, and(2), tok(NAME), opt_rule(as_name))
-DEF_RULE(dotted_as_name, nc, and(2), rule(dotted_name), opt_rule(as_name))
-DEF_RULE(as_name, nc, ident | and(2), tok(KW_AS), tok(NAME))
+DEF_RULE(dotted_as_name, nc, and_ident(2), rule(dotted_name), opt_rule(as_name))
+DEF_RULE(as_name, nc, and_ident(2), tok(KW_AS), tok(NAME))
DEF_RULE(import_as_names, nc, list_with_end, rule(import_as_name), tok(DEL_COMMA))
DEF_RULE(dotted_as_names, nc, list, rule(dotted_as_name), tok(DEL_COMMA))
DEF_RULE(dotted_name, nc, list, tok(NAME), tok(DEL_PERIOD))
@@ -155,9 +161,9 @@ DEF_RULE(global_stmt, c(global_stmt), and(2), tok(KW_GLOBAL), rule(name_list))
DEF_RULE(nonlocal_stmt, c(nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list))
DEF_RULE(name_list, nc, list, tok(NAME), tok(DEL_COMMA))
DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra))
-DEF_RULE(assert_stmt_extra, nc, ident | and(2), tok(DEL_COMMA), rule(test))
+DEF_RULE(assert_stmt_extra, nc, and_ident(2), tok(DEL_COMMA), rule(test))
-// compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
+// compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
// if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
// while_stmt: 'while' test ':' suite ['else' ':' suite]
// for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
@@ -167,8 +173,15 @@ DEF_RULE(assert_stmt_extra, nc, ident | and(2), tok(DEL_COMMA), rule(test))
// with_stmt: 'with' with_item (',' with_item)* ':' suite
// with_item: test ['as' expr]
// suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
+// async_stmt: 'async' (funcdef | with_stmt | for_stmt)
+#if MICROPY_PY_ASYNC_AWAIT
+DEF_RULE(compound_stmt, nc, or(9), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated), rule(async_stmt))
+DEF_RULE(async_stmt, c(async_stmt), and(2), tok(KW_ASYNC), rule(async_stmt_2))
+DEF_RULE(async_stmt_2, nc, or(3), rule(funcdef), rule(with_stmt), rule(for_stmt))
+#else
DEF_RULE(compound_stmt, nc, or(8), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated))
+#endif
DEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt))
DEF_RULE(if_stmt_elif_list, nc, one_or_more, rule(if_stmt_elif))
DEF_RULE(if_stmt_elif, nc, and(4), tok(KW_ELIF), rule(test), tok(DEL_COLON), rule(suite))
@@ -176,18 +189,18 @@ DEF_RULE(while_stmt, c(while_stmt), and(5), tok(KW_WHILE), rule(test), tok(DEL_C
DEF_RULE(for_stmt, c(for_stmt), and(7), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(testlist), tok(DEL_COLON), rule(suite), opt_rule(else_stmt))
DEF_RULE(try_stmt, c(try_stmt), and(4), tok(KW_TRY), tok(DEL_COLON), rule(suite), rule(try_stmt_2))
DEF_RULE(try_stmt_2, nc, or(2), rule(try_stmt_except_and_more), rule(try_stmt_finally))
-DEF_RULE(try_stmt_except_and_more, nc, and(3), rule(try_stmt_except_list), opt_rule(else_stmt), opt_rule(try_stmt_finally))
+DEF_RULE(try_stmt_except_and_more, nc, and_ident(3), rule(try_stmt_except_list), opt_rule(else_stmt), opt_rule(try_stmt_finally))
DEF_RULE(try_stmt_except, nc, and(4), tok(KW_EXCEPT), opt_rule(try_stmt_as_name), tok(DEL_COLON), rule(suite))
-DEF_RULE(try_stmt_as_name, nc, and(2), rule(test), opt_rule(as_name))
+DEF_RULE(try_stmt_as_name, nc, and_ident(2), rule(test), opt_rule(as_name))
DEF_RULE(try_stmt_except_list, nc, one_or_more, rule(try_stmt_except))
DEF_RULE(try_stmt_finally, nc, and(3), tok(KW_FINALLY), tok(DEL_COLON), rule(suite))
-DEF_RULE(else_stmt, nc, ident | and(3), tok(KW_ELSE), tok(DEL_COLON), rule(suite))
+DEF_RULE(else_stmt, nc, and_ident(3), tok(KW_ELSE), tok(DEL_COLON), rule(suite))
DEF_RULE(with_stmt, c(with_stmt), and(4), tok(KW_WITH), rule(with_stmt_list), tok(DEL_COLON), rule(suite))
DEF_RULE(with_stmt_list, nc, list, rule(with_item), tok(DEL_COMMA))
-DEF_RULE(with_item, nc, and(2), rule(test), opt_rule(with_item_as))
-DEF_RULE(with_item_as, nc, ident | and(2), tok(KW_AS), rule(expr))
+DEF_RULE(with_item, nc, and_ident(2), rule(test), opt_rule(with_item_as))
+DEF_RULE(with_item_as, nc, and_ident(2), tok(KW_AS), rule(expr))
DEF_RULE(suite, nc, or(2), rule(suite_block), rule(simple_stmt))
-DEF_RULE(suite_block, nc, and(4), tok(NEWLINE), tok(INDENT), rule(suite_block_stmts), tok(DEDENT))
+DEF_RULE(suite_block, nc, and_ident(4), tok(NEWLINE), tok(INDENT), rule(suite_block_stmts), tok(DEDENT))
DEF_RULE(suite_block_stmts, c(generic_all_nodes), one_or_more, rule(stmt))
// test: or_test ['if' or_test 'else' test] | lambdef
@@ -196,11 +209,11 @@ DEF_RULE(suite_block_stmts, c(generic_all_nodes), one_or_more, rule(stmt))
// lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
DEF_RULE(test, nc, or(2), rule(lambdef), rule(test_if_expr))
-DEF_RULE(test_if_expr, c(test_if_expr), and(2), rule(or_test), opt_rule(test_if_else))
+DEF_RULE(test_if_expr, c(test_if_expr), and_ident(2), rule(or_test), opt_rule(test_if_else))
DEF_RULE(test_if_else, nc, and(4), tok(KW_IF), rule(or_test), tok(KW_ELSE), rule(test))
DEF_RULE(test_nocond, nc, or(2), rule(lambdef_nocond), rule(or_test))
-DEF_RULE(lambdef, c(lambdef), blank | and(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test))
-DEF_RULE(lambdef_nocond, c(lambdef), blank | and(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test_nocond))
+DEF_RULE(lambdef, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test))
+DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test_nocond))
// or_test: and_test ('or' and_test)*
// and_test: not_test ('and' not_test)*
@@ -215,7 +228,8 @@ DEF_RULE(lambdef_nocond, c(lambdef), blank | and(4), tok(KW_LAMBDA), opt_rule(va
// arith_expr: term (('+'|'-') term)*
// term: factor (('*'|'/'|'%'|'//') factor)*
// factor: ('+'|'-'|'~') factor | power
-// power: atom trailer* ['**' factor]
+// power: atom_expr ['**' factor]
+// atom_expr: 'await' atom trailer* | atom trailer*
DEF_RULE(or_test, c(or_test), list, rule(and_test), tok(KW_OR))
DEF_RULE(and_test, c(and_test), list, rule(not_test), tok(KW_AND))
@@ -237,11 +251,18 @@ DEF_RULE(arith_op, nc, or(2), tok(OP_PLUS), tok(OP_MINUS))
DEF_RULE(term, c(term), list, rule(factor), rule(term_op))
DEF_RULE(term_op, nc, or(4), tok(OP_STAR), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH))
DEF_RULE(factor, nc, or(2), rule(factor_2), rule(power))
-DEF_RULE(factor_2, c(factor_2), and(2), rule(factor_op), rule(factor))
+DEF_RULE(factor_2, c(factor_2), and_ident(2), rule(factor_op), rule(factor))
DEF_RULE(factor_op, nc, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE))
-DEF_RULE(power, c(power), and(3), rule(atom), opt_rule(power_trailers), opt_rule(power_dbl_star))
-DEF_RULE(power_trailers, c(power_trailers), one_or_more, rule(trailer))
-DEF_RULE(power_dbl_star, nc, ident | and(2), tok(OP_DBL_STAR), rule(factor))
+DEF_RULE(power, c(power), and_ident(2), rule(atom_expr), opt_rule(power_dbl_star))
+#if MICROPY_PY_ASYNC_AWAIT
+DEF_RULE(atom_expr, nc, or(2), rule(atom_expr_await), rule(atom_expr_normal))
+DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom), opt_rule(atom_expr_trailers))
+#else
+DEF_RULE(atom_expr, nc, or(1), rule(atom_expr_normal))
+#endif
+DEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers))
+DEF_RULE(atom_expr_trailers, c(atom_expr_trailers), one_or_more, rule(trailer))
+DEF_RULE(power_dbl_star, nc, and_ident(2), tok(OP_DBL_STAR), rule(factor))
// atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'
// testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
@@ -253,10 +274,10 @@ DEF_RULE(atom_paren, c(atom_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(atom_2
DEF_RULE(atom_2b, nc, or(2), rule(yield_expr), rule(testlist_comp))
DEF_RULE(atom_bracket, c(atom_bracket), and(3), tok(DEL_BRACKET_OPEN), opt_rule(testlist_comp), tok(DEL_BRACKET_CLOSE))
DEF_RULE(atom_brace, c(atom_brace), and(3), tok(DEL_BRACE_OPEN), opt_rule(dictorsetmaker), tok(DEL_BRACE_CLOSE))
-DEF_RULE(testlist_comp, nc, and(2), rule(testlist_comp_2), opt_rule(testlist_comp_3))
+DEF_RULE(testlist_comp, nc, and_ident(2), rule(testlist_comp_2), opt_rule(testlist_comp_3))
DEF_RULE(testlist_comp_2, nc, or(2), rule(star_expr), rule(test))
DEF_RULE(testlist_comp_3, nc, or(2), rule(comp_for), rule(testlist_comp_3b))
-DEF_RULE(testlist_comp_3b, nc, ident | and(2), tok(DEL_COMMA), opt_rule(testlist_comp_3c))
+DEF_RULE(testlist_comp_3b, nc, and_ident(2), tok(DEL_COMMA), opt_rule(testlist_comp_3c))
DEF_RULE(testlist_comp_3c, nc, list_with_end, rule(testlist_comp_2), tok(DEL_COMMA))
DEF_RULE(trailer, nc, or(3), rule(trailer_paren), rule(trailer_bracket), rule(trailer_period))
DEF_RULE(trailer_paren, c(trailer_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE))
@@ -270,11 +291,11 @@ DEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME))
#if MICROPY_PY_BUILTINS_SLICE
DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA))
DEF_RULE(subscript, nc, or(2), rule(subscript_3), rule(subscript_2))
-DEF_RULE(subscript_2, c(subscript_2), and(2), rule(test), opt_rule(subscript_3))
+DEF_RULE(subscript_2, c(subscript_2), and_ident(2), rule(test), opt_rule(subscript_3))
DEF_RULE(subscript_3, c(subscript_3), and(2), tok(DEL_COLON), opt_rule(subscript_3b))
DEF_RULE(subscript_3b, nc, or(2), rule(subscript_3c), rule(subscript_3d))
DEF_RULE(subscript_3c, nc, and(2), tok(DEL_COLON), opt_rule(test))
-DEF_RULE(subscript_3d, nc, and(2), rule(test), opt_rule(sliceop))
+DEF_RULE(subscript_3d, nc, and_ident(2), rule(test), opt_rule(sliceop))
DEF_RULE(sliceop, nc, and(2), tok(DEL_COLON), opt_rule(test))
#else
DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA))
@@ -288,10 +309,10 @@ DEF_RULE(exprlist, nc, list_with_end, rule(exprlist_2), tok(DEL_COMMA))
DEF_RULE(exprlist_2, nc, or(2), rule(star_expr), rule(expr))
DEF_RULE(testlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA))
// TODO dictorsetmaker lets through more than is allowed
-DEF_RULE(dictorsetmaker, nc, and(2), rule(dictorsetmaker_item), opt_rule(dictorsetmaker_tail))
+DEF_RULE(dictorsetmaker, nc, and_ident(2), rule(dictorsetmaker_item), opt_rule(dictorsetmaker_tail))
#if MICROPY_PY_BUILTINS_SET
-DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and(2), rule(test), opt_rule(dictorsetmaker_colon))
-DEF_RULE(dictorsetmaker_colon, nc, ident | and(2), tok(DEL_COLON), rule(test))
+DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and_ident(2), rule(test), opt_rule(dictorsetmaker_colon))
+DEF_RULE(dictorsetmaker_colon, nc, and_ident(2), tok(DEL_COLON), rule(test))
#else
DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and(3), rule(test), tok(DEL_COLON), rule(test))
#endif
@@ -301,8 +322,8 @@ DEF_RULE(dictorsetmaker_list2, nc, list_with_end, rule(dictorsetmaker_item), tok
// classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
-DEF_RULE(classdef, c(classdef), blank | and(5), tok(KW_CLASS), tok(NAME), opt_rule(classdef_2), tok(DEL_COLON), rule(suite))
-DEF_RULE(classdef_2, nc, ident | and(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE))
+DEF_RULE(classdef, c(classdef), and_blank(5), tok(KW_CLASS), tok(NAME), opt_rule(classdef_2), tok(DEL_COLON), rule(suite))
+DEF_RULE(classdef_2, nc, and_ident(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE))
// arglist: (argument ',')* (argument [','] | '*' test (',' argument)* [',' '**' test] | '**' test)
@@ -319,11 +340,11 @@ DEF_RULE(arglist_dbl_star, nc, and(2), tok(OP_DBL_STAR), rule(test))
// comp_for: 'for' exprlist 'in' or_test [comp_iter]
// comp_if: 'if' test_nocond [comp_iter]
-DEF_RULE(argument, nc, and(2), rule(test), opt_rule(argument_2))
+DEF_RULE(argument, nc, and_ident(2), rule(test), opt_rule(argument_2))
DEF_RULE(argument_2, nc, or(2), rule(comp_for), rule(argument_3))
-DEF_RULE(argument_3, nc, ident | and(2), tok(DEL_EQUAL), rule(test))
+DEF_RULE(argument_3, nc, and_ident(2), tok(DEL_EQUAL), rule(test))
DEF_RULE(comp_iter, nc, or(2), rule(comp_for), rule(comp_if))
-DEF_RULE(comp_for, nc, blank | and(5), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(or_test), opt_rule(comp_iter))
+DEF_RULE(comp_for, nc, and_blank(5), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(or_test), opt_rule(comp_iter))
DEF_RULE(comp_if, nc, and(3), tok(KW_IF), rule(test_nocond), opt_rule(comp_iter))
// # not used in grammar, but may appear in "node" passed from Parser to Compiler
diff --git a/py/lexer.c b/py/lexer.c
index 76abedd451..1639740d34 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -234,6 +234,10 @@ STATIC const char *tok_kw[] = {
"and",
"as",
"assert",
+ #if MICROPY_PY_ASYNC_AWAIT
+ "async",
+ "await",
+ #endif
"break",
"class",
"continue",
diff --git a/py/lexer.h b/py/lexer.h
index 36d1e99d23..463be5fffc 100644
--- a/py/lexer.h
+++ b/py/lexer.h
@@ -63,6 +63,10 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_KW_AND,
MP_TOKEN_KW_AS,
MP_TOKEN_KW_ASSERT,
+ #if MICROPY_PY_ASYNC_AWAIT
+ MP_TOKEN_KW_ASYNC,
+ MP_TOKEN_KW_AWAIT,
+ #endif
MP_TOKEN_KW_BREAK,
MP_TOKEN_KW_CLASS,
MP_TOKEN_KW_CONTINUE,
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index e8adb0cbb6..c00ec1eb28 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -9,11 +9,15 @@ from __future__ import print_function
import re
import sys
-# codepoint2name is different in Python 2 to Python 3
+# Python 2/3 compatibility:
+# - iterating through bytes is different
+# - codepoint2name lives in a different module
import platform
if platform.python_version_tuple()[0] == '2':
+ ord_bytes = ord
from htmlentitydefs import codepoint2name
elif platform.python_version_tuple()[0] == '3':
+ ord_bytes = lambda x:x
from html.entities import codepoint2name
codepoint2name[ord('-')] = 'hyphen';
@@ -23,6 +27,7 @@ codepoint2name[ord('\'')] = 'squot'
codepoint2name[ord(',')] = 'comma'
codepoint2name[ord('.')] = 'dot'
codepoint2name[ord(':')] = 'colon'
+codepoint2name[ord(';')] = 'semicolon'
codepoint2name[ord('/')] = 'slash'
codepoint2name[ord('%')] = 'percent'
codepoint2name[ord('#')] = 'hash'
@@ -36,6 +41,13 @@ codepoint2name[ord('*')] = 'star'
codepoint2name[ord('!')] = 'bang'
codepoint2name[ord('\\')] = 'backslash'
codepoint2name[ord('+')] = 'plus'
+codepoint2name[ord('$')] = 'dollar'
+codepoint2name[ord('=')] = 'equals'
+codepoint2name[ord('?')] = 'question'
+codepoint2name[ord('@')] = 'at_sign'
+codepoint2name[ord('^')] = 'caret'
+codepoint2name[ord('|')] = 'pipe'
+codepoint2name[ord('~')] = 'tilde'
# this must match the equivalent function in qstr.c
def compute_hash(qstr, bytes_hash):
@@ -45,7 +57,17 @@ def compute_hash(qstr, bytes_hash):
# Make sure that valid hash is never zero, zero means "hash not computed"
return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1
-def do_work(infiles):
+def qstr_escape(qst):
+ def esc_char(m):
+ c = ord(m.group(0))
+ try:
+ name = codepoint2name[c]
+ except KeyError:
+ name = '0x%02x' % c
+ return "_" + name + '_'
+ return re.sub(r'[^A-Za-z0-9_]', esc_char, qst)
+
+def parse_input_headers(infiles):
# read the qstrs in from the input files
qcfgs = {}
qstrs = {}
@@ -71,7 +93,13 @@ def do_work(infiles):
# get the qstr value
qstr = match.group(1)
- ident = re.sub(r'[^A-Za-z0-9_]', lambda s: "_" + codepoint2name[ord(s.group(0))] + "_", qstr)
+
+ # special case to specify control characters
+ if qstr == '\\n':
+ qstr = '\n'
+
+ # work out the corresponding qstr name
+ ident = qstr_escape(qstr)
# don't add duplicates
if ident in qstrs:
@@ -84,10 +112,30 @@ def do_work(infiles):
sys.stderr.write("ERROR: Empty preprocessor output - check for errors above\n")
sys.exit(1)
+ return qcfgs, qstrs
+
+def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr):
+ qhash = compute_hash(qstr, cfg_bytes_hash)
+ if all(32 <= ord(c) <= 126 and c != '\\' for c in qstr):
+ # qstr is all printable ASCII so render it as-is (for easier debugging)
+ qlen = len(qstr)
+ qdata = qstr
+ else:
+ # qstr contains non-printable codes so render entire thing as hex pairs
+ qbytes = qstr.encode('utf8')
+ qlen = len(qbytes)
+ qdata = ''.join(('\\x%02x' % ord_bytes(b)) for b in qbytes)
+ if qlen >= (1 << (8 * cfg_bytes_len)):
+ print('qstr is too long:', qstr)
+ assert False
+ qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len))
+ qhash_str = ('\\x%02x' * cfg_bytes_hash) % tuple(((qhash >> (8 * i)) & 0xff) for i in range(cfg_bytes_hash))
+ return '(const byte*)"%s%s" "%s"' % (qhash_str, qlen_str, qdata)
+
+def print_qstr_data(qcfgs, qstrs):
# get config variables
cfg_bytes_len = int(qcfgs['BYTES_IN_LEN'])
cfg_bytes_hash = int(qcfgs['BYTES_IN_HASH'])
- cfg_max_len = 1 << (8 * cfg_bytes_len)
# print out the starter of the generated C header file
print('// This file was automatically generated by makeqstrdata.py')
@@ -98,16 +146,12 @@ def do_work(infiles):
# go through each qstr and print it out
for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
- qhash = compute_hash(qstr, cfg_bytes_hash)
- # Calculate len of str, taking escapes into account
- qlen = len(qstr.replace("\\\\", "-").replace("\\", ""))
- qdata = qstr.replace('"', '\\"')
- if qlen >= cfg_max_len:
- print('qstr is too long:', qstr)
- assert False
- qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len))
- qhash_str = ('\\x%02x' * cfg_bytes_hash) % tuple(((qhash >> (8 * i)) & 0xff) for i in range(cfg_bytes_hash))
- print('QDEF(MP_QSTR_%s, (const byte*)"%s%s" "%s")' % (ident, qhash_str, qlen_str, qdata))
+ qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr)
+ print('QDEF(MP_QSTR_%s, %s)' % (ident, qbytes))
+
+def do_work(infiles):
+ qcfgs, qstrs = parse_input_headers(infiles)
+ print_qstr_data(qcfgs, qstrs)
if __name__ == "__main__":
do_work(sys.argv[1:])
diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py
new file mode 100644
index 0000000000..194d901d26
--- /dev/null
+++ b/py/makeqstrdefs.py
@@ -0,0 +1,109 @@
+"""
+This script processes the output from the C preprocessor and extracts all
+qstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'.
+
+This script works with Python 2.6, 2.7, 3.3 and 3.4.
+"""
+
+import re
+import argparse
+import os
+
+# Blacklist of qstrings that are specially handled in further
+# processing and should be ignored
+QSTRING_BLACK_LIST = {'NULL', 'number_of', }
+
+
+def write_out(fname, output):
+ if output:
+ for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
+ fname = fname.replace(m, r)
+ with open(args.output_dir + "/" + fname + ".qstr", "w") as f:
+ f.write("\n".join(output) + "\n")
+
+def process_file(f):
+ output = []
+ last_fname = None
+ for line in f:
+ # match gcc-like output (# n "file") and msvc-like output (#line n "file")
+ if line and (line[0:2] == "# " or line[0:5] == "#line"):
+ m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line)
+ assert m is not None
+ fname = m.group(1)
+ if fname[0] == "/" or not fname.endswith(".c"):
+ continue
+ if fname != last_fname:
+ write_out(last_fname, output)
+ output = []
+ last_fname = fname
+ continue
+ for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line):
+ name = match.replace('MP_QSTR_', '')
+ if name not in QSTRING_BLACK_LIST:
+ output.append('Q(' + name + ')')
+
+ write_out(last_fname, output)
+ return ""
+
+
+def cat_together():
+ import glob
+ import hashlib
+ hasher = hashlib.md5()
+ all_lines = []
+ outf = open(args.output_dir + "/out", "wb")
+ for fname in glob.glob(args.output_dir + "/*.qstr"):
+ with open(fname, "rb") as f:
+ lines = f.readlines()
+ all_lines += lines
+ all_lines.sort()
+ all_lines = b"\n".join(all_lines)
+ outf.write(all_lines)
+ outf.close()
+ hasher.update(all_lines)
+ new_hash = hasher.hexdigest()
+ #print(new_hash)
+ old_hash = None
+ try:
+ with open(args.output_file + ".hash") as f:
+ old_hash = f.read()
+ except IOError:
+ pass
+ if old_hash != new_hash:
+ print("QSTR updated")
+ try:
+ # rename below might fail if file exists
+ os.remove(args.output_file)
+ except:
+ pass
+ os.rename(args.output_dir + "/out", args.output_file)
+ with open(args.output_file + ".hash", "w") as f:
+ f.write(new_hash)
+ else:
+ print("QSTR not updated")
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Generates qstr definitions from a specified source')
+
+ parser.add_argument('command',
+ help='Command (split/cat)')
+ parser.add_argument('input_filename',
+ help='Name of the input file (when not specified, the script reads standard input)')
+ parser.add_argument('output_dir',
+ help='Output directory to store individual qstr files')
+ parser.add_argument('output_file',
+ help='Name of the output file with collected qstrs')
+
+ args = parser.parse_args()
+ try:
+ os.makedirs(args.output_dir)
+ except OSError:
+ pass
+
+ if args.command == "split":
+ with open(args.input_filename) as infile:
+ process_file(infile)
+
+ if args.command == "cat":
+ cat_together()
diff --git a/py/map.c b/py/map.c
index e7aae7cb06..445b206603 100644
--- a/py/map.c
+++ b/py/map.c
@@ -45,19 +45,26 @@ const mp_map_t mp_const_empty_map = {
.table = NULL,
};
-// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
-// prefixed with zero for the empty case.
-STATIC uint32_t doubling_primes[] = {0, 7, 19, 43, 89, 179, 347, 647, 1229, 2297, 4243, 7829, 14347, 26017, 47149, 84947, 152443, 273253, 488399, 869927, 1547173, 2745121, 4861607};
-
-STATIC mp_uint_t get_doubling_prime_greater_or_equal_to(mp_uint_t x) {
- for (size_t i = 0; i < MP_ARRAY_SIZE(doubling_primes); i++) {
- if (doubling_primes[i] >= x) {
- return doubling_primes[i];
+// This table of sizes is used to control the growth of hash tables.
+// The first set of sizes are chosen so the allocation fits exactly in a
+// 4-word GC block, and it's not so important for these small values to be
+// prime. The latter sizes are prime and increase at an increasing rate.
+STATIC uint16_t hash_allocation_sizes[] = {
+ 0, 2, 4, 6, 8, 10, 12, // +2
+ 17, 23, 29, 37, 47, 59, 73, // *1.25
+ 97, 127, 167, 223, 293, 389, 521, 691, 919, 1223, 1627, 2161, // *1.33
+ 3229, 4831, 7243, 10861, 16273, 24407, 36607, 54907, // *1.5
+};
+
+STATIC mp_uint_t get_hash_alloc_greater_or_equal_to(mp_uint_t x) {
+ for (size_t i = 0; i < MP_ARRAY_SIZE(hash_allocation_sizes); i++) {
+ if (hash_allocation_sizes[i] >= x) {
+ return hash_allocation_sizes[i];
}
}
// ran out of primes in the table!
// return something sensible, at least make it odd
- return x | 1;
+ return (x + x / 2) | 1;
}
/******************************************************************************/
@@ -118,7 +125,7 @@ void mp_map_clear(mp_map_t *map) {
STATIC void mp_map_rehash(mp_map_t *map) {
mp_uint_t old_alloc = map->alloc;
- mp_uint_t new_alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
+ mp_uint_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1);
mp_map_elem_t *old_table = map->table;
mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc);
// If we reach this point, table resizing succeeded, now we can edit the old map.
@@ -298,7 +305,7 @@ void mp_set_init(mp_set_t *set, mp_uint_t n) {
STATIC void mp_set_rehash(mp_set_t *set) {
mp_uint_t old_alloc = set->alloc;
mp_obj_t *old_table = set->table;
- set->alloc = get_doubling_prime_greater_or_equal_to(set->alloc + 1);
+ set->alloc = get_hash_alloc_greater_or_equal_to(set->alloc + 1);
set->used = 0;
set->table = m_new0(mp_obj_t, set->alloc);
for (mp_uint_t i = 0; i < old_alloc; i++) {
diff --git a/py/mkrules.mk b/py/mkrules.mk
index 9cbef1ac5a..3ed4afec19 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -46,21 +46,47 @@ vpath %.c . $(TOP)
$(BUILD)/%.o: %.c
$(call compile_c)
+# List all native flags since the current build system doesn't have
+# the micropython configuration available. However, these flags are
+# needed to extract all qstrings
+QSTR_GEN_EXTRA_CFLAGS += -D__QSTR_EXTRACT -DN_X64 -DN_X86 -DN_THUMB -DN_ARM
+QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp
+
+vpath %.c . $(TOP)
+
$(BUILD)/%.pp: %.c
$(ECHO) "PreProcess $<"
$(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $<
-# The following rule uses | to create an order only prereuisite. Order only
+# The following rule uses | to create an order only prerequisite. Order only
# prerequisites only get built if they don't exist. They don't cause timestamp
# checking to be performed.
#
# We don't know which source files actually need the generated.h (since
# it is #included from str.h). The compiler generated dependencies will cause
# the right .o's to get recompiled if the generated.h file changes. Adding
-# an order-only dependendency to all of the .o's will cause the generated .h
+# an order-only dependency to all of the .o's will cause the generated .h
# to get built before we try to compile any of them.
$(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h
+$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) | $(HEADER_BUILD)/mpversion.h
+ $(ECHO) "GEN $@"
+ $(Q)if [ "$?" = "" ]; then \
+ echo "QSTR Looks like -B used, trying to emulate"; \
+ $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $^ >$(HEADER_BUILD)/qstr.i.last; \
+ else \
+ $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $? >$(HEADER_BUILD)/qstr.i.last; \
+ fi
+
+$(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last
+ $(ECHO) "GEN $@"
+ $(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
+ $(Q)touch $@
+
+$(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split
+ $(ECHO) "GEN $@"
+ $(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
+
# $(sort $(var)) removes duplicates
#
# The net effect of this, is it causes the objects to depend on the
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index 859cb11116..87446f7fae 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -439,6 +439,7 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
mp_print_str(&mp_plat_print, "\n");
#endif
#if MICROPY_CAN_OVERRIDE_BUILTINS
+ // Set "_" special variable
mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o};
mp_type_module.attr(MP_OBJ_FROM_PTR(&mp_module_builtins), MP_QSTR__, dest);
#endif
@@ -703,6 +704,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) },
{ MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) },
{ MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) },
+ #if MICROPY_PY_ASYNC_AWAIT
+ { MP_ROM_QSTR(MP_QSTR_StopAsyncIteration), MP_ROM_PTR(&mp_type_StopAsyncIteration) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_StopIteration), MP_ROM_PTR(&mp_type_StopIteration) },
{ MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) },
{ MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) },
diff --git a/py/modcollections.c b/py/modcollections.c
index e43de184a7..dceaa203de 100644
--- a/py/modcollections.c
+++ b/py/modcollections.c
@@ -29,7 +29,7 @@
#if MICROPY_PY_COLLECTIONS
STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__collections) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) },
{ MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) },
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
{ MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) },
@@ -40,7 +40,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_collections_globals, mp_module_collections
const mp_obj_module_t mp_module_collections = {
.base = { &mp_type_module },
- .name = MP_QSTR__collections,
+ .name = MP_QSTR_ucollections,
.globals = (mp_obj_dict_t*)&mp_module_collections_globals,
};
diff --git a/py/modio.c b/py/modio.c
index 96805d2911..423315081f 100644
--- a/py/modio.c
+++ b/py/modio.c
@@ -124,7 +124,7 @@ STATIC const mp_obj_type_t bufwriter_type = {
#endif // MICROPY_PY_IO_BUFFEREDWRITER
STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__io) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) },
// Note: mp_builtin_open_obj should be defined by port, it's not
// part of the core.
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
@@ -147,7 +147,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table);
const mp_obj_module_t mp_module_io = {
.base = { &mp_type_module },
- .name = MP_QSTR__io,
+ .name = MP_QSTR_uio,
.globals = (mp_obj_dict_t*)&mp_module_io_globals,
};
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 6c2db2f1fc..42ef19b72c 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -234,7 +234,7 @@
// Whether generated code can persist independently of the VM/runtime instance
// This is enabled automatically when needed by other features
#ifndef MICROPY_PERSISTENT_CODE
-#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE)
+#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY)
#endif
// Whether to emit x64 native code
@@ -526,9 +526,19 @@ typedef double mp_float_t;
#define MICROPY_MODULE_WEAK_LINKS (0)
#endif
-// Whether frozen modules are supported
+// Whether frozen modules are supported in the form of strings
+#ifndef MICROPY_MODULE_FROZEN_STR
+#define MICROPY_MODULE_FROZEN_STR (0)
+#endif
+
+// Whether frozen modules are supported in the form of .mpy files
+#ifndef MICROPY_MODULE_FROZEN_MPY
+#define MICROPY_MODULE_FROZEN_MPY (0)
+#endif
+
+// Convenience macro for whether frozen modules are supported
#ifndef MICROPY_MODULE_FROZEN
-#define MICROPY_MODULE_FROZEN (0)
+#define MICROPY_MODULE_FROZEN (MICROPY_MODULE_FROZEN_STR || MICROPY_MODULE_FROZEN_MPY)
#endif
// Whether you can override builtins in the builtins module
@@ -564,6 +574,11 @@ typedef double mp_float_t;
#define MICROPY_PY_DESCRIPTORS (0)
#endif
+// Support for async/await/async for/async with
+#ifndef MICROPY_PY_ASYNC_AWAIT
+#define MICROPY_PY_ASYNC_AWAIT (1)
+#endif
+
// Whether str object is proper unicode
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
@@ -837,6 +852,10 @@ typedef double mp_float_t;
#define MICROPY_PY_MACHINE (0)
#endif
+#ifndef MICROPY_PY_MACHINE_I2C
+#define MICROPY_PY_MACHINE_I2C (0)
+#endif
+
#ifndef MICROPY_PY_USSL
#define MICROPY_PY_USSL (0)
#endif
@@ -845,6 +864,10 @@ typedef double mp_float_t;
#define MICROPY_PY_WEBSOCKET (0)
#endif
+#ifndef MICROPY_PY_FRAMEBUF
+#define MICROPY_PY_FRAMEBUF (0)
+#endif
+
/*****************************************************************************/
/* Hooks for a port to add builtins */
diff --git a/py/obj.h b/py/obj.h
index 25f31ea5ad..6b0f441752 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -83,7 +83,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 1) != 0); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
-#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
+#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 3) == 2); }
@@ -109,7 +109,7 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 3) == 1); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2)
-#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 2) | 1))
+#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1))
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 3) == 3); }
@@ -135,7 +135,7 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 1) != 0); }
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
-#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
+#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))
#define mp_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000))
#define mp_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000))
@@ -561,6 +561,7 @@ extern const mp_obj_type_t mp_type_OSError;
extern const mp_obj_type_t mp_type_TimeoutError;
extern const mp_obj_type_t mp_type_OverflowError;
extern const mp_obj_type_t mp_type_RuntimeError;
+extern const mp_obj_type_t mp_type_StopAsyncIteration;
extern const mp_obj_type_t mp_type_StopIteration;
extern const mp_obj_type_t mp_type_SyntaxError;
extern const mp_obj_type_t mp_type_SystemExit;
diff --git a/py/objexcept.c b/py/objexcept.c
index d8aecb80f0..adf17b08d0 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -197,6 +197,9 @@ MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION_BASE(Exception)
+ #if MICROPY_PY_ASYNC_AWAIT
+ MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception)
+ #endif
MP_DEFINE_EXCEPTION(StopIteration, Exception)
MP_DEFINE_EXCEPTION(ArithmeticError, Exception)
MP_DEFINE_EXCEPTION_BASE(ArithmeticError)
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 93df7ce13f..2480b0a4b8 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -99,6 +99,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance));
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
if (self->code_state.ip == 0) {
+ // Trying to resume already stopped generator
*ret_val = MP_OBJ_STOP_ITERATION;
return MP_VM_RETURN_NORMAL;
}
diff --git a/py/objmodule.c b/py/objmodule.c
index 5fd7b82c5b..8c3cb85e67 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -137,10 +137,10 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
{ MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_module_array) },
#endif
#if MICROPY_PY_IO
- { MP_ROM_QSTR(MP_QSTR__io), MP_ROM_PTR(&mp_module_io) },
+ { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) },
#endif
#if MICROPY_PY_COLLECTIONS
- { MP_ROM_QSTR(MP_QSTR__collections), MP_ROM_PTR(&mp_module_collections) },
+ { MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) },
#endif
#if MICROPY_PY_STRUCT
{ MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) },
@@ -196,6 +196,12 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
#if MICROPY_PY_WEBSOCKET
{ MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) },
#endif
+#if MICROPY_PY_WEBREPL
+ { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) },
+#endif
+#if MICROPY_PY_FRAMEBUF
+ { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) },
+#endif
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES
diff --git a/py/objstr.c b/py/objstr.c
index 0c2d904035..d0d090b995 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -564,7 +564,7 @@ STATIC mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
- mp_obj_t new_args[2] = {pos_args[0], MP_OBJ_NEW_QSTR(MP_QSTR__backslash_n)};
+ mp_obj_t new_args[2] = {pos_args[0], MP_OBJ_NEW_QSTR(MP_QSTR__0x0a_)};
return str_split_internal(2, new_args, SPLITLINES | (args.keepends.u_bool ? KEEP : 0));
}
#endif
diff --git a/py/parse.c b/py/parse.c
index b57e82d459..3daa5ff83e 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -56,8 +56,6 @@
#define RULE_ARG_RULE (0x2000)
#define RULE_ARG_OPT_RULE (0x3000)
-#define ADD_BLANK_NODE(rule) ((rule->act & RULE_ACT_ADD_BLANK) != 0)
-
// (un)comment to use rule names; for debugging
//#define USE_RULE_NAME (1)
@@ -80,10 +78,10 @@ enum {
RULE_const_object, // special node for a constant, generic Python object
};
-#define ident (RULE_ACT_ALLOW_IDENT)
-#define blank (RULE_ACT_ADD_BLANK)
#define or(n) (RULE_ACT_OR | n)
#define and(n) (RULE_ACT_AND | n)
+#define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT)
+#define and_blank(n) (RULE_ACT_AND | n | RULE_ACT_ADD_BLANK)
#define one_or_more (RULE_ACT_LIST | 2)
#define list (RULE_ACT_LIST | 1)
#define list_with_end (RULE_ACT_LIST | 3)
@@ -563,11 +561,10 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
// this node is of the form <x> = <y>
mp_parse_node_t pn0 = peek_result(parser, 1);
if (MP_PARSE_NODE_IS_ID(pn0)
- && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_power)
+ && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal)
&& MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t*)pn1)->nodes[0])
&& MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn1)->nodes[0]) == MP_QSTR_const
&& MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t*)pn1)->nodes[1], RULE_trailer_paren)
- && MP_PARSE_NODE_IS_NULL(((mp_parse_node_struct_t*)pn1)->nodes[2])
) {
// code to assign dynamic constants: id = const(value)
@@ -599,13 +596,11 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
#endif
#if MICROPY_COMP_MODULE_CONST
- } else if (rule->rule_id == RULE_power) {
- mp_parse_node_t pn0 = peek_result(parser, 2);
- mp_parse_node_t pn1 = peek_result(parser, 1);
- mp_parse_node_t pn2 = peek_result(parser, 0);
+ } else if (rule->rule_id == RULE_atom_expr_normal) {
+ mp_parse_node_t pn0 = peek_result(parser, 1);
+ mp_parse_node_t pn1 = peek_result(parser, 0);
if (!(MP_PARSE_NODE_IS_ID(pn0)
- && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period)
- && MP_PARSE_NODE_IS_NULL(pn2))) {
+ && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period))) {
return false;
}
// id1.id2
@@ -833,25 +828,6 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// matched the rule, so now build the corresponding parse_node
- // count number of arguments for the parse_node
- i = 0;
- bool emit_rule = false;
- for (size_t x = 0; x < n; ++x) {
- if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
- mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK;
- if (tok_kind >= MP_TOKEN_NAME) {
- emit_rule = true;
- }
- if (tok_kind == MP_TOKEN_NAME) {
- // only tokens which were names are pushed to stack
- i += 1;
- }
- } else {
- // rules are always pushed
- i += 1;
- }
- }
-
#if !MICROPY_ENABLE_DOC_STRING
// this code discards lonely statements, such as doc strings
if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
@@ -871,35 +847,29 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
}
#endif
- // always emit these rules, even if they have only 1 argument
- if (rule->rule_id == RULE_expr_stmt || rule->rule_id == RULE_yield_stmt) {
- emit_rule = true;
- }
-
- // if a rule has the RULE_ACT_ALLOW_IDENT bit set then this
- // rule should not be emitted if it has only 1 argument
- if (rule->act & RULE_ACT_ALLOW_IDENT) {
- emit_rule = false;
- }
-
- // always emit these rules, and add an extra blank node at the end (to be used by the compiler to store data)
- if (ADD_BLANK_NODE(rule)) {
- emit_rule = true;
- push_result_node(&parser, MP_PARSE_NODE_NULL);
- i += 1;
- }
-
+ // count number of arguments for the parse node
+ i = 0;
size_t num_not_nil = 0;
- for (size_t x = 0; x < i; ++x) {
- if (peek_result(&parser, x) != MP_PARSE_NODE_NULL) {
- num_not_nil += 1;
+ for (size_t x = n; x > 0;) {
+ --x;
+ if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
+ mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK;
+ if (tok_kind == MP_TOKEN_NAME) {
+ // only tokens which were names are pushed to stack
+ i += 1;
+ num_not_nil += 1;
+ }
+ } else {
+ // rules are always pushed
+ if (peek_result(&parser, i) != MP_PARSE_NODE_NULL) {
+ num_not_nil += 1;
+ }
+ i += 1;
}
}
- if (emit_rule || num_not_nil != 1) {
- // need to add rule when num_not_nil==0 for, eg, atom_paren, testlist_comp_3b
- push_result_rule(&parser, rule_src_line, rule, i);
- } else {
- // single result, leave it on stack
+
+ if (num_not_nil == 1 && (rule->act & RULE_ACT_ALLOW_IDENT)) {
+ // this rule has only 1 argument and should not be emitted
mp_parse_node_t pn = MP_PARSE_NODE_NULL;
for (size_t x = 0; x < i; ++x) {
mp_parse_node_t pn2 = pop_result(&parser);
@@ -908,6 +878,16 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
}
}
push_result_node(&parser, pn);
+ } else {
+ // this rule must be emitted
+
+ if (rule->act & RULE_ACT_ADD_BLANK) {
+ // and add an extra blank node at the end (used by the compiler to store data)
+ push_result_node(&parser, MP_PARSE_NODE_NULL);
+ i += 1;
+ }
+
+ push_result_rule(&parser, rule_src_line, rule, i);
}
break;
}
diff --git a/py/py.mk b/py/py.mk
index fff20b9cd8..db173156ed 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -7,6 +7,12 @@ HEADER_BUILD = $(BUILD)/genhdr
# file containing qstr defs for the core Python bit
PY_QSTR_DEFS = $(PY_SRC)/qstrdefs.h
+# If qstr autogeneration is not disabled we specify the output header
+# for all collected qstrings.
+ifneq ($(QSTR_AUTOGEN_DISABLE),1)
+QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h
+endif
+
# some code is performance bottleneck and compiled with other optimization options
CSUPEROPT = -O3
@@ -94,6 +100,7 @@ PY_O_BASENAME = \
parsenum.o \
emitglue.o \
runtime.o \
+ runtime_utils.o \
nativeglue.o \
stackctrl.o \
argcheck.o \
@@ -167,9 +174,12 @@ PY_O_BASENAME = \
../extmod/moduhashlib.o \
../extmod/modubinascii.o \
../extmod/machine_mem.o \
+ ../extmod/machine_i2c.o \
../extmod/modussl.o \
../extmod/modurandom.o \
../extmod/modwebsocket.o \
+ ../extmod/modwebrepl.o \
+ ../extmod/modframebuf.o \
../extmod/fsusermount.o \
../extmod/vfs_fat.o \
../extmod/vfs_fat_ffconf.o \
@@ -182,6 +192,10 @@ PY_O_BASENAME = \
# prepend the build destination prefix to the py object files
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
+# Sources that may contain qstrings
+SRC_QSTR_IGNORE = nlr% emitnx% emitnthumb% emitnarm%
+SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c)
+
# Anything that depends on FORCE will be considered out-of-date
FORCE:
.PHONY: FORCE
@@ -194,14 +208,13 @@ $(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)
MPCONFIGPORT_MK = $(wildcard mpconfigport.mk)
# qstr data
-
# Adding an order only dependency on $(HEADER_BUILD) causes $(HEADER_BUILD) to get
# created before we run the script to generate the .h
# Note: we need to protect the qstr names from the preprocessor, so we wrap
# the lines in "" and then unwrap after the preprocessor is finished.
-$(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD)
+$(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD)
$(ECHO) "GEN $@"
- $(Q)cat $(PY_QSTR_DEFS) $(QSTR_DEFS) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | sed 's/^"\(Q(.*)\)"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h
+ $(Q)cat $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | sed 's/^"\(Q(.*)\)"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h
$(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@
# emitters
diff --git a/py/qstr.c b/py/qstr.c
index 4268946fbe..24793ff8a3 100644
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -87,20 +87,29 @@ mp_uint_t qstr_compute_hash(const byte *data, size_t len) {
return hash;
}
-STATIC const qstr_pool_t const_pool = {
+const qstr_pool_t mp_qstr_const_pool = {
NULL, // no previous pool
0, // no previous pool
10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below)
- MP_QSTR_number_of, // corresponds to number of strings in array just below
+ MP_QSTRnumber_of, // corresponds to number of strings in array just below
{
+#ifndef __QSTR_EXTRACT
#define QDEF(id, str) str,
#include "genhdr/qstrdefs.generated.h"
#undef QDEF
+#endif
},
};
+#ifdef MICROPY_QSTR_EXTRA_POOL
+extern const qstr_pool_t MICROPY_QSTR_EXTRA_POOL;
+#define CONST_POOL MICROPY_QSTR_EXTRA_POOL
+#else
+#define CONST_POOL mp_qstr_const_pool
+#endif
+
void qstr_init(void) {
- MP_STATE_VM(last_pool) = (qstr_pool_t*)&const_pool; // we won't modify the const_pool since it has no allocated room left
+ MP_STATE_VM(last_pool) = (qstr_pool_t*)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left
MP_STATE_VM(qstr_last_chunk) = NULL;
}
@@ -258,7 +267,7 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si
*n_qstr = 0;
*n_str_data_bytes = 0;
*n_total_bytes = 0;
- for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &const_pool; pool = pool->prev) {
+ for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) {
*n_pool += 1;
*n_qstr += pool->len;
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
@@ -275,7 +284,7 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si
#if MICROPY_PY_MICROPYTHON_MEM_INFO
void qstr_dump_data(void) {
- for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &const_pool; pool = pool->prev) {
+ for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) {
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
mp_printf(&mp_plat_print, "Q(%s)\n", Q_GET_DATA(*q));
}
diff --git a/py/qstr.h b/py/qstr.h
index b68f60a443..1989ebe962 100644
--- a/py/qstr.h
+++ b/py/qstr.h
@@ -37,10 +37,12 @@
// first entry in enum will be MP_QSTR_NULL=0, which indicates invalid/no qstr
enum {
+#ifndef __QSTR_EXTRACT
#define QDEF(id, str) id,
#include "genhdr/qstrdefs.generated.h"
#undef QDEF
- MP_QSTR_number_of,
+#endif
+ MP_QSTRnumber_of, // no underscore so it can't clash with any of the above
};
typedef size_t qstr;
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index f5e06f1a52..c98a253a69 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -36,461 +36,11 @@ QCFG(BYTES_IN_HASH, MICROPY_QSTR_BYTES_IN_HASH)
Q()
Q(*)
Q(_)
-Q(__build_class__)
-Q(__class__)
-Q(__doc__)
-Q(__import__)
-Q(__init__)
-Q(__new__)
-Q(__locals__)
-Q(__main__)
-Q(__module__)
-Q(__name__)
-Q(__dict__)
-Q(__hash__)
-Q(__next__)
-Q(__qualname__)
-Q(__path__)
-Q(__repl_print__)
-#if MICROPY_PY___FILE__
-Q(__file__)
-#endif
-
-Q(__bool__)
-Q(__contains__)
-Q(__enter__)
-Q(__exit__)
-Q(__len__)
-Q(__iter__)
-Q(__getitem__)
-Q(__setitem__)
-Q(__delitem__)
-Q(__add__)
-Q(__sub__)
-Q(__repr__)
-Q(__str__)
-#if MICROPY_PY_DESCRIPTORS
-Q(__get__)
-Q(__set__)
-Q(__delete__)
-#endif
-Q(__getattr__)
-Q(__del__)
-Q(__call__)
-Q(__lt__)
-Q(__gt__)
-Q(__eq__)
-Q(__le__)
-Q(__ge__)
-Q(__reversed__)
-#if MICROPY_PY_ALL_SPECIAL_METHODS
-Q(__mul__)
-Q(__truediv__)
-Q(__floordiv__)
-Q(__iadd__)
-Q(__isub__)
-Q(__invert__)
-Q(__neg__)
-Q(__pos__)
-#endif
-
-Q(micropython)
-Q(bytecode)
-Q(const)
-
-#if MICROPY_EMIT_NATIVE
-Q(native)
-Q(viper)
-Q(uint)
-Q(ptr)
-Q(ptr8)
-Q(ptr16)
-Q(ptr32)
-#endif
-
-#if MICROPY_EMIT_INLINE_THUMB
-Q(asm_thumb)
-Q(label)
-Q(align)
-Q(data)
-Q(uint)
-Q(nop)
-Q(mov)
-Q(and_)
-Q(cmp)
-Q(add)
-Q(sub)
-Q(lsl)
-Q(lsr)
-Q(asr)
-Q(ldr)
-Q(ldrb)
-Q(ldrh)
-Q(str)
-Q(strb)
-Q(strh)
-Q(b)
-Q(bl)
-Q(bx)
-Q(push)
-Q(pop)
-Q(cpsid)
-Q(cpsie)
-Q(wfi)
-Q(clz)
-Q(rbit)
-Q(movw)
-Q(movt)
-Q(movwt)
-Q(mrs)
-Q(sdiv)
-Q(udiv)
-Q(ldrex)
-Q(strex)
-#if MICROPY_EMIT_INLINE_THUMB_FLOAT
-Q(vcmp)
-Q(vneg)
-Q(vcvt_f32_s32)
-Q(vcvt_s32_f32)
-Q(vsqrt)
-Q(vmov)
-Q(vmrs)
-Q(vldr)
-Q(vstr)
-#endif
-#endif
-
-Q(builtins)
-
-Q(Ellipsis)
-Q(StopIteration)
-#if MICROPY_PY_BUILTINS_NOTIMPLEMENTED
-Q(NotImplemented)
-#endif
-
-Q(BaseException)
-Q(ArithmeticError)
-Q(AssertionError)
-Q(AttributeError)
-Q(BufferError)
-Q(EOFError)
-Q(Exception)
-Q(FileExistsError)
-Q(FileNotFoundError)
-Q(FloatingPointError)
-Q(GeneratorExit)
-Q(ImportError)
-Q(IndentationError)
-Q(IndexError)
-Q(KeyboardInterrupt)
-Q(KeyError)
-Q(LookupError)
-Q(MemoryError)
-Q(NameError)
-Q(NotImplementedError)
-Q(OSError)
-#if MICROPY_PY_BUILTINS_TIMEOUTERROR
-Q(TimeoutError)
-#endif
-Q(OverflowError)
-Q(RuntimeError)
-Q(SyntaxError)
-Q(SystemExit)
-Q(TypeError)
-Q(UnboundLocalError)
-Q(ValueError)
-#if MICROPY_EMIT_NATIVE
-Q(ViperTypeError)
-#endif
-Q(ZeroDivisionError)
-#if MICROPY_PY_BUILTINS_STR_UNICODE
-Q(UnicodeError)
-#endif
-
-Q(None)
-Q(False)
-Q(True)
-Q(object)
-
-Q(NoneType)
-
-#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
-Q(OrderedDict)
-#endif
-
-Q(abs)
-Q(all)
-Q(any)
-Q(args)
-#if MICROPY_PY_ARRAY
-Q(array)
-#endif
-Q(bin)
-Q({:#b})
-Q(bool)
-#if MICROPY_PY_BUILTINS_BYTEARRAY
-Q(bytearray)
-#endif
-#if MICROPY_PY_BUILTINS_MEMORYVIEW
-Q(memoryview)
-#endif
-Q(bytes)
-Q(callable)
-Q(chr)
-Q(classmethod)
-Q(_collections)
-#if MICROPY_PY_BUILTINS_COMPLEX
-Q(complex)
-Q(real)
-Q(imag)
-#endif
-Q(dict)
-Q(dir)
-Q(divmod)
-#if MICROPY_PY_BUILTINS_ENUMERATE
-Q(enumerate)
-#endif
-Q(eval)
-Q(exec)
-#if MICROPY_PY_BUILTINS_EXECFILE
-Q(execfile)
-#endif
-#if MICROPY_PY_BUILTINS_FILTER
-Q(filter)
-#endif
-#if MICROPY_PY_BUILTINS_FLOAT
-Q(float)
-#endif
-Q(from_bytes)
-Q(getattr)
-Q(setattr)
-Q(globals)
-Q(hasattr)
-Q(hash)
-Q(hex)
-Q(%#x)
-Q(id)
-Q(int)
-Q(isinstance)
-Q(issubclass)
-Q(iter)
-Q(len)
-Q(list)
-Q(locals)
-Q(map)
-#if MICROPY_PY_BUILTINS_MIN_MAX
-Q(max)
-Q(min)
-Q(default)
-#endif
-Q(namedtuple)
-Q(next)
-Q(oct)
Q(%#o)
-Q(open)
-Q(ord)
-Q(path)
-Q(pow)
-Q(print)
-Q(range)
-Q(read)
-Q(repr)
-Q(reversed)
-Q(round)
-Q(sorted)
-Q(staticmethod)
-Q(sum)
-Q(super)
-Q(str)
-Q(sys)
-Q(to_bytes)
-Q(tuple)
-Q(type)
-Q(value)
-Q(write)
-Q(zip)
-
-#if MICROPY_PY_BUILTINS_COMPILE
-Q(compile)
-Q(code)
-Q(single)
-#endif
-
-Q(sep)
-Q(end)
-
-#if MICROPY_PY_BUILTINS_RANGE_ATTRS
-Q(step)
-Q(stop)
-#endif
-
-Q(clear)
-Q(copy)
-Q(fromkeys)
-Q(get)
-Q(items)
-Q(keys)
-Q(pop)
-Q(popitem)
-Q(setdefault)
-Q(update)
-Q(values)
-Q(append)
-Q(close)
-Q(send)
-Q(throw)
-Q(count)
-Q(extend)
-Q(index)
-Q(remove)
-Q(insert)
-Q(pop)
-Q(sort)
-Q(join)
-Q(strip)
-Q(lstrip)
-Q(rstrip)
-Q(format)
-Q(key)
-Q(reverse)
-Q(add)
-Q(clear)
-Q(copy)
-Q(pop)
-Q(remove)
-Q(find)
-Q(rfind)
-Q(rindex)
-Q(split)
-#if MICROPY_PY_BUILTINS_STR_SPLITLINES
-Q(splitlines)
-Q(keepends)
+Q(%#x)
+Q({:#b})
Q(\n)
-#endif
-Q(rsplit)
-Q(startswith)
-Q(endswith)
-Q(replace)
-Q(partition)
-Q(rpartition)
-Q(lower)
-Q(upper)
-Q(isspace)
-Q(isalpha)
-Q(isdigit)
-Q(isupper)
-Q(islower)
-Q(iterable)
-Q(start)
-
-Q(bound_method)
-Q(closure)
-Q(dict_view)
-Q(function)
-Q(generator)
-Q(iterator)
-Q(module)
-Q(slice)
-
-#if MICROPY_PY_BUILTINS_SET
-Q(discard)
-Q(difference)
-Q(difference_update)
-Q(intersection)
-Q(intersection_update)
-Q(isdisjoint)
-Q(issubset)
-Q(issuperset)
-Q(set)
-Q(symmetric_difference)
-Q(symmetric_difference_update)
-Q(union)
-Q(update)
-#endif
-
-#if MICROPY_PY_BUILTINS_FROZENSET
-Q(frozenset)
-#endif
-
-#if MICROPY_PY_MATH || MICROPY_PY_CMATH
-Q(math)
-Q(e)
-Q(pi)
-Q(sqrt)
-Q(pow)
-Q(exp)
-#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
-Q(expm1)
-#endif
-Q(log)
-#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
-Q(log2)
-Q(log10)
-Q(cosh)
-Q(sinh)
-Q(tanh)
-Q(acosh)
-Q(asinh)
-Q(atanh)
-#endif
-Q(cos)
-Q(sin)
-Q(tan)
-Q(acos)
-Q(asin)
-Q(atan)
-Q(atan2)
-Q(ceil)
-Q(copysign)
-Q(fabs)
-Q(fmod)
-Q(floor)
-Q(isfinite)
-Q(isinf)
-Q(isnan)
-Q(trunc)
-Q(modf)
-Q(frexp)
-Q(ldexp)
-Q(degrees)
-Q(radians)
-#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
-Q(erf)
-Q(erfc)
-Q(gamma)
-Q(lgamma)
-#endif
-#endif
-
-#if MICROPY_PY_CMATH
-Q(cmath)
-Q(phase)
-Q(polar)
-Q(rect)
-#endif
-
-#if MICROPY_PY_MICROPYTHON_MEM_INFO
-#if MICROPY_MEM_STATS
-Q(mem_total)
-Q(mem_current)
-Q(mem_peak)
-#endif
-Q(mem_info)
-Q(qstr_info)
-#if MICROPY_STACK_CHECK
-Q(stack_use)
-#endif
-#endif
-#if MICROPY_ENABLE_GC
-Q(heap_lock)
-Q(heap_unlock)
-#endif
-
-#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
-Q(alloc_emergency_exception_buf)
-#endif
Q(maximum recursion depth exceeded)
-
Q(<module>)
Q(<lambda>)
Q(<listcomp>)
@@ -499,265 +49,12 @@ Q(<setcomp>)
Q(<genexpr>)
Q(<string>)
Q(<stdin>)
-
-#if MICROPY_CPYTHON_COMPAT
-Q(encode)
-Q(decode)
Q(utf-8)
-#endif
-
-#if MICROPY_PY_SYS
-Q(argv)
-Q(byteorder)
-Q(big)
-Q(exit)
-Q(little)
-#ifdef MICROPY_PY_SYS_PLATFORM
-Q(platform)
-#endif
-Q(stdin)
-Q(stdout)
-Q(stderr)
-#if MICROPY_PY_SYS_STDIO_BUFFER
-Q(buffer)
-#endif
-Q(version)
-Q(version_info)
-#if MICROPY_PY_ATTRTUPLE
-Q(name)
-#endif
-Q(implementation)
-#if MICROPY_PY_SYS_MAXSIZE
-Q(maxsize)
-#endif
-#if MICROPY_PY_SYS_MODULES
-Q(modules)
-#endif
-#if MICROPY_PY_SYS_EXC_INFO
-Q(exc_info)
-#endif
-Q(print_exception)
-#endif
-
-#if MICROPY_PY_STRUCT
-Q(struct)
-Q(ustruct)
-Q(pack)
-Q(pack_into)
-Q(unpack)
-Q(unpack_from)
-Q(calcsize)
-#endif
-
-#if MICROPY_PY_UCTYPES
-Q(uctypes)
-Q(struct)
-Q(sizeof)
-Q(addressof)
-Q(bytes_at)
-Q(bytearray_at)
-
-Q(NATIVE)
-Q(LITTLE_ENDIAN)
-Q(BIG_ENDIAN)
-
-Q(VOID)
-
-Q(UINT8)
-Q(INT8)
-Q(UINT16)
-Q(INT16)
-Q(UINT32)
-Q(INT32)
-Q(UINT64)
-Q(INT64)
-
-Q(BFUINT8)
-Q(BFINT8)
-Q(BFUINT16)
-Q(BFINT16)
-Q(BFUINT32)
-Q(BFINT32)
-
-Q(FLOAT32)
-Q(FLOAT64)
-
-Q(ARRAY)
-Q(PTR)
-//Q(BITFIELD)
-
-Q(BF_POS)
-Q(BF_LEN)
-#endif
-
-#if MICROPY_PY_IO
-Q(_io)
-Q(readall)
-Q(readinto)
-Q(readline)
-Q(readlines)
-Q(seek)
-Q(tell)
-Q(FileIO)
-Q(TextIOWrapper)
-Q(StringIO)
-Q(BytesIO)
-Q(getvalue)
-Q(file)
-Q(mode)
-Q(r)
-Q(encoding)
-#if MICROPY_PY_IO_BUFFEREDWRITER
-Q(BufferedWriter)
-#endif
-#endif
-
-#if MICROPY_PY_GC
-Q(gc)
-Q(collect)
-Q(disable)
-Q(enable)
-Q(isenabled)
-Q(mem_free)
-Q(mem_alloc)
-#endif
-
-#if MICROPY_PY_BUILTINS_PROPERTY
-Q(property)
-Q(getter)
-Q(setter)
-Q(deleter)
-Q(doc)
-#endif
-
-#if MICROPY_PY_UZLIB
-Q(uzlib)
-Q(decompress)
-#endif
-
-#if MICROPY_PY_UJSON
-Q(ujson)
-Q(dumps)
-Q(loads)
-#endif
-
-#if MICROPY_PY_URE
-Q(ure)
-Q(compile)
-Q(match)
-Q(search)
-Q(group)
-Q(DEBUG)
-#endif
-#if MICROPY_PY_UHEAPQ
-Q(uheapq)
-Q(heappush)
-Q(heappop)
-Q(heapify)
-#endif
-
-#if MICROPY_PY_UHASHLIB
-Q(uhashlib)
-Q(update)
-Q(digest)
-Q(sha256)
-Q(sha1)
-#endif
-
-#if MICROPY_PY_UBINASCII
-Q(ubinascii)
-Q(hexlify)
-Q(unhexlify)
-Q(a2b_base64)
-Q(b2a_base64)
-#endif
-
-#if MICROPY_PY_MACHINE
-Q(umachine)
-Q(mem)
-Q(mem8)
-Q(mem16)
-Q(mem32)
-#endif
-
-#if MICROPY_PY_USSL
-Q(ussl)
-Q(wrap_socket)
-#endif
-
-#if MICROPY_PY_LWIP
-// for lwip module
-Q(lwip)
-Q(reset)
-Q(callback)
-Q(socket)
-Q(AF_INET)
-Q(AF_INET6)
-Q(SOCK_STREAM)
-Q(SOCK_DGRAM)
-Q(SOCK_RAW)
-Q(SOL_SOCKET)
-Q(SO_REUSEADDR)
-// for lwip.socket
-Q(close)
-Q(bind)
-Q(listen)
-Q(accept)
-Q(connect)
-Q(send)
-Q(recv)
-Q(sendto)
-Q(recvfrom)
-Q(settimeout)
-Q(setsockopt)
-Q(makefile)
-#if MICROPY_PY_LWIP_SLIP
-// for lwip.slip
-Q(slip)
-Q(status)
-#endif
-#endif
-
-#if MICROPY_FSUSERMOUNT
-// for user-mountable block devices
-Q(mount)
-Q(umount)
-Q(readonly)
-Q(mkfs)
-Q(listdir)
-Q(mkdir)
-Q(remove)
-Q(rename)
-Q(readblocks)
-Q(writeblocks)
-Q(ioctl)
-Q(sync)
-Q(count)
-#endif
-
-#if MICROPY_PY_OS_DUPTERM
-Q(dupterm)
-#endif
-
-#if MICROPY_PY_URANDOM
-Q(urandom)
-Q(getrandbits)
-Q(seed)
-#if MICROPY_PY_URANDOM_EXTRA_FUNCS
-Q(randrange)
-Q(randint)
-Q(choice)
-Q(random)
-Q(uniform)
-#endif
-#endif
-
-#if MICROPY_VFS_FAT
-Q(VfsFat)
-Q(flush)
-#endif
-
-#if MICROPY_PY_WEBSOCKET
-Q(websocket)
-#endif
+// The following qstrings not referenced from anywhere in the sources
+Q(__locals__)
+Q(BufferError)
+Q(FileExistsError)
+Q(FileNotFoundError)
+Q(FloatingPointError)
+Q(UnboundLocalError)
diff --git a/py/repl.c b/py/repl.c
index de0e8a4e76..7bd8759084 100644
--- a/py/repl.c
+++ b/py/repl.c
@@ -57,6 +57,9 @@ bool mp_repl_continue_with_input(const char *input) {
|| str_startswith_word(input, "with")
|| str_startswith_word(input, "def")
|| str_startswith_word(input, "class")
+ #if MICROPY_PY_ASYNC_AWAIT
+ || str_startswith_word(input, "async")
+ #endif
;
// check for unmatched open bracket, quote or escape quote
diff --git a/py/runtime.c b/py/runtime.c
index adbab579f0..67534c4b5e 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -704,7 +704,12 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const
assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above
for (mp_uint_t i = 0; i < map->alloc; i++) {
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
- args2[args2_len++] = map->table[i].key;
+ // the key must be a qstr, so intern it if it's a string
+ mp_obj_t key = map->table[i].key;
+ if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
+ key = mp_obj_str_intern(key);
+ }
+ args2[args2_len++] = key;
args2[args2_len++] = map->table[i].value;
}
}
@@ -726,7 +731,12 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const
}
mp_obj_t *items;
mp_obj_get_array_fixed_n(item, 2, &items);
- args2[args2_len++] = items[0];
+ // the key must be a qstr, so intern it if it's a string
+ mp_obj_t key = items[0];
+ if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
+ key = mp_obj_str_intern(key);
+ }
+ args2[args2_len++] = key;
args2[args2_len++] = items[1];
}
}
diff --git a/py/runtime.h b/py/runtime.h
index 1b58f4728f..3e325a31b3 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -95,6 +95,9 @@ mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
mp_obj_t mp_call_function_n_kw(mp_obj_t fun, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
mp_obj_t mp_call_method_n_kw(mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
mp_obj_t mp_call_method_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const mp_obj_t *args);
+// Call function and catch/dump exception - for Python callbacks from C code
+void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg);
+void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
typedef struct _mp_call_args_t {
mp_obj_t fun;
diff --git a/py/runtime_utils.c b/py/runtime_utils.c
new file mode 100644
index 0000000000..e0495495aa
--- /dev/null
+++ b/py/runtime_utils.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2015 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/obj.h"
+#include "py/nlr.h"
+
+void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_call_function_1(fun, arg);
+ nlr_pop();
+ } else {
+ mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
+ }
+}
+
+void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_call_function_2(fun, arg1, arg2);
+ nlr_pop();
+ } else {
+ mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
+ }
+}
diff --git a/py/vm.c b/py/vm.c
index b8d38f78e4..bd5bae115e 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1144,7 +1144,8 @@ yield:
if (ret_kind == MP_VM_RETURN_NORMAL) {
// Pop exhausted gen
sp--;
- if (ret_value == MP_OBJ_NULL) {
+ // TODO: When ret_value can be MP_OBJ_NULL here??
+ if (ret_value == MP_OBJ_NULL || ret_value == MP_OBJ_STOP_ITERATION) {
// Optimize StopIteration
// TODO: get StopIteration's value
PUSH(mp_const_none);