diff options
author | Damien George <damien.p.george@gmail.com> | 2017-04-18 22:52:18 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2017-04-22 21:46:32 +1000 |
commit | 5335942b599d85263d3c18eb99ff5ebd04a8bc98 (patch) | |
tree | e01e62224ae9d1b70cb5a57fa8c33630badea559 /py | |
parent | 0dd6a59c895b6de4841b4e372069aa9392c24d5f (diff) | |
download | micropython-5335942b599d85263d3c18eb99ff5ebd04a8bc98.tar.gz micropython-5335942b599d85263d3c18eb99ff5ebd04a8bc98.zip |
py/compile: Refactor handling of special super() call.
This patch refactors the handling of the special super() call within the
compiler. It removes the need for a global (to the compiler) state variable
which keeps track of whether the subject of an expression is super. The
handling of super() is now done entirely within one function, which makes
the compiler a bit cleaner and allows to easily add more optimisations to
super calls.
Changes to the code size are:
bare-arm: +12
minimal: +0
unix x64: +48
unix nanbox: -16
stmhal: +4
cc3200: +0
esp8266: -56
Diffstat (limited to 'py')
-rw-r--r-- | py/compile.c | 105 | ||||
-rw-r--r-- | py/grammar.h | 2 |
2 files changed, 67 insertions, 40 deletions
diff --git a/py/compile.c b/py/compile.c index 2110867291..42c2cc3a24 100644 --- a/py/compile.c +++ b/py/compile.c @@ -115,7 +115,6 @@ typedef struct _compiler_t { uint8_t is_repl; uint8_t pass; // holds enum type pass_kind_t - uint8_t func_arg_is_super; // used to compile special case of super() function call uint8_t have_star; // try to keep compiler clean from nlr @@ -762,7 +761,6 @@ STATIC qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pn if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) { parents = MP_PARSE_NODE_NULL; } - comp->func_arg_is_super = false; compile_trailer_paren_helper(comp, parents, false, 2); // return its name (the 'C' in class C(...):") @@ -836,7 +834,6 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { // nodes[1] contains arguments to the decorator function, if any if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) { // call the decorator function with the arguments in nodes[1] - comp->func_arg_is_super = false; compile_node(comp, pns_decorator->nodes[1]); } } @@ -2175,36 +2172,83 @@ STATIC void compile_factor_2(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 the subject of the expression + compile_node(comp, pns->nodes[0]); - compile_generic_all_nodes(comp, pns); -} + // compile_atom_expr_await may call us with a NULL node + if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { + return; + } -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); -} + // get the array of trailers (known to be an array of PARSE_NODE_STRUCT) + size_t num_trail = 1; + mp_parse_node_struct_t **pns_trail = (mp_parse_node_struct_t**)&pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_atom_expr_trailers) { + num_trail = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_trail[0]); + pns_trail = (mp_parse_node_struct_t**)&pns_trail[0]->nodes[0]; + } -STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) { - // function to call is on top of stack + // the current index into the array of trailers + size_t i = 0; - // this is to handle special super() call - if (MP_PARSE_NODE_IS_NULL(pn_arglist) && comp->func_arg_is_super && comp->scope_cur->kind == SCOPE_FUNCTION) { + // handle special super() call + if (comp->scope_cur->kind == SCOPE_FUNCTION + && MP_PARSE_NODE_IS_ID(pns->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren + && MP_PARSE_NODE_IS_NULL(pns_trail[0]->nodes[0])) { + // at this point we have matched "super()" within a function + + // load the class for super to search for a parent compile_load_id(comp, MP_QSTR___class__); + // look for first argument to function (assumes it's "self") - for (int i = 0; i < comp->scope_cur->id_info_len; i++) { - id_info_t *id = &comp->scope_cur->id_info[i]; + bool found = false; + id_info_t *id = &comp->scope_cur->id_info[0]; + for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) { if (id->flags & ID_FLAG_IS_PARAM) { - // first argument found; load it and call super + // first argument found; load it compile_load_id(comp, id->qst); - EMIT_ARG(call_function, 2, 0, 0); - return; + found = true; + break; } } - compile_syntax_error(comp, MP_PARSE_NODE_NULL, "super() call cannot find self"); // really a TypeError - return; + if (!found) { + compile_syntax_error(comp, (mp_parse_node_t)pns_trail[0], + "super() can't find self"); // really a TypeError + return; + } + + // a super() call + EMIT_ARG(call_function, 2, 0, 0); + i = 1; + } + + // compile the remaining trailers + for (; i < num_trail; i++) { + if (i + 1 < num_trail + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i]) == PN_trailer_period + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i + 1]) == PN_trailer_paren) { + // optimisation for method calls a.f(...), following PyPy + mp_parse_node_struct_t *pns_period = pns_trail[i]; + mp_parse_node_struct_t *pns_paren = pns_trail[i + 1]; + EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0])); + compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); + i += 1; + } else { + // node is one of: trailer_paren, trailer_bracket, trailer_period + compile_node(comp, (mp_parse_node_t)pns_trail[i]); + } } +} + +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) { + // function to call is on top of stack // get the list of arguments mp_parse_node_t *args; @@ -2285,23 +2329,6 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar } } -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)) { - // optimisation for method calls a.f(...), following PyPy - mp_parse_node_struct_t *pns_period = (mp_parse_node_struct_t*)pns->nodes[i]; - mp_parse_node_struct_t *pns_paren = (mp_parse_node_struct_t*)pns->nodes[i + 1]; - EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0])); // get the method - compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); - i += 1; - } else { - compile_node(comp, pns->nodes[i]); - } - comp->func_arg_is_super = false; - } -} - // pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) { assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2); diff --git a/py/grammar.h b/py/grammar.h index e8041c0e08..930d96dc15 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -261,7 +261,7 @@ DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom), DEF_RULE_NC(atom_expr, 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_NC(atom_expr_trailers, one_or_more, rule(trailer)) DEF_RULE_NC(power_dbl_star, and_ident(2), tok(OP_DBL_STAR), rule(factor)) // atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' |