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
This commit is contained in:
parent
0dd6a59c89
commit
5335942b59
107
py/compile.c
107
py/compile.c
|
@ -115,7 +115,6 @@ typedef struct _compiler_t {
|
||||||
|
|
||||||
uint8_t is_repl;
|
uint8_t is_repl;
|
||||||
uint8_t pass; // holds enum type pass_kind_t
|
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;
|
uint8_t have_star;
|
||||||
|
|
||||||
// try to keep compiler clean from nlr
|
// 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)) {
|
if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) {
|
||||||
parents = MP_PARSE_NODE_NULL;
|
parents = MP_PARSE_NODE_NULL;
|
||||||
}
|
}
|
||||||
comp->func_arg_is_super = false;
|
|
||||||
compile_trailer_paren_helper(comp, parents, false, 2);
|
compile_trailer_paren_helper(comp, parents, false, 2);
|
||||||
|
|
||||||
// return its name (the 'C' in class C(...):")
|
// 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
|
// nodes[1] contains arguments to the decorator function, if any
|
||||||
if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
|
if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
|
||||||
// call the decorator function with the arguments in 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]);
|
compile_node(comp, pns_decorator->nodes[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2175,10 +2172,74 @@ 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) {
|
STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||||
// this is to handle special super() call
|
// compile the subject of the expression
|
||||||
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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// the current index into the array of trailers
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
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
|
||||||
|
compile_load_id(comp, id->qst);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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) {
|
STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||||
|
@ -2189,23 +2250,6 @@ STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||||
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {
|
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
|
// function to call is on top of stack
|
||||||
|
|
||||||
// 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) {
|
|
||||||
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];
|
|
||||||
if (id->flags & ID_FLAG_IS_PARAM) {
|
|
||||||
// first argument found; load it and call super
|
|
||||||
compile_load_id(comp, id->qst);
|
|
||||||
EMIT_ARG(call_function, 2, 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "super() call cannot find self"); // really a TypeError
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the list of arguments
|
// get the list of arguments
|
||||||
mp_parse_node_t *args;
|
mp_parse_node_t *args;
|
||||||
int n_args = mp_parse_node_extract_list(&pn_arglist, PN_arglist, &args);
|
int n_args = mp_parse_node_extract_list(&pn_arglist, PN_arglist, &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
|
// 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) {
|
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);
|
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);
|
||||||
|
|
|
@ -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))
|
DEF_RULE_NC(atom_expr, or(1), rule(atom_expr_normal))
|
||||||
#endif
|
#endif
|
||||||
DEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers))
|
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))
|
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'
|
// atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
tok(4)
|
tok(4)
|
||||||
[ 4] rule(22) (n=4)
|
[ 4] rule(22) (n=4)
|
||||||
id(i)
|
id(i)
|
||||||
[ 4] rule(45) (n=1)
|
[ 4] rule(44) (n=1)
|
||||||
NULL
|
NULL
|
||||||
[ 5] rule(8) (n=0)
|
[ 5] rule(8) (n=0)
|
||||||
NULL
|
NULL
|
||||||
|
|
Loading…
Reference in New Issue