Skip to content

Commit 5335942

Browse files
committed
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
1 parent 0dd6a59 commit 5335942

3 files changed

Lines changed: 68 additions & 41 deletions

File tree

py/compile.c

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ typedef struct _compiler_t {
115115

116116
uint8_t is_repl;
117117
uint8_t pass; // holds enum type pass_kind_t
118-
uint8_t func_arg_is_super; // used to compile special case of super() function call
119118
uint8_t have_star;
120119

121120
// 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
762761
if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) {
763762
parents = MP_PARSE_NODE_NULL;
764763
}
765-
comp->func_arg_is_super = false;
766764
compile_trailer_paren_helper(comp, parents, false, 2);
767765

768766
// 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) {
836834
// nodes[1] contains arguments to the decorator function, if any
837835
if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
838836
// call the decorator function with the arguments in nodes[1]
839-
comp->func_arg_is_super = false;
840837
compile_node(comp, pns_decorator->nodes[1]);
841838
}
842839
}
@@ -2175,36 +2172,83 @@ STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
21752172
}
21762173

21772174
STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) {
2178-
// this is to handle special super() call
2179-
comp->func_arg_is_super = MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super;
2175+
// compile the subject of the expression
2176+
compile_node(comp, pns->nodes[0]);
21802177

2181-
compile_generic_all_nodes(comp, pns);
2182-
}
2178+
// compile_atom_expr_await may call us with a NULL node
2179+
if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
2180+
return;
2181+
}
21832182

2184-
STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
2185-
compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power
2186-
EMIT_ARG(binary_op, MP_BINARY_OP_POWER);
2187-
}
2183+
// get the array of trailers (known to be an array of PARSE_NODE_STRUCT)
2184+
size_t num_trail = 1;
2185+
mp_parse_node_struct_t **pns_trail = (mp_parse_node_struct_t**)&pns->nodes[1];
2186+
if (MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_atom_expr_trailers) {
2187+
num_trail = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_trail[0]);
2188+
pns_trail = (mp_parse_node_struct_t**)&pns_trail[0]->nodes[0];
2189+
}
21882190

2189-
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {
2190-
// function to call is on top of stack
2191+
// the current index into the array of trailers
2192+
size_t i = 0;
21912193

2192-
// this is to handle special super() call
2193-
if (MP_PARSE_NODE_IS_NULL(pn_arglist) && comp->func_arg_is_super && comp->scope_cur->kind == SCOPE_FUNCTION) {
2194+
// handle special super() call
2195+
if (comp->scope_cur->kind == SCOPE_FUNCTION
2196+
&& MP_PARSE_NODE_IS_ID(pns->nodes[0])
2197+
&& MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super
2198+
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren
2199+
&& MP_PARSE_NODE_IS_NULL(pns_trail[0]->nodes[0])) {
2200+
// at this point we have matched "super()" within a function
2201+
2202+
// load the class for super to search for a parent
21942203
compile_load_id(comp, MP_QSTR___class__);
2204+
21952205
// look for first argument to function (assumes it's "self")
2196-
for (int i = 0; i < comp->scope_cur->id_info_len; i++) {
2197-
id_info_t *id = &comp->scope_cur->id_info[i];
2206+
bool found = false;
2207+
id_info_t *id = &comp->scope_cur->id_info[0];
2208+
for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) {
21982209
if (id->flags & ID_FLAG_IS_PARAM) {
2199-
// first argument found; load it and call super
2210+
// first argument found; load it
22002211
compile_load_id(comp, id->qst);
2201-
EMIT_ARG(call_function, 2, 0, 0);
2202-
return;
2212+
found = true;
2213+
break;
22032214
}
22042215
}
2205-
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "super() call cannot find self"); // really a TypeError
2206-
return;
2216+
if (!found) {
2217+
compile_syntax_error(comp, (mp_parse_node_t)pns_trail[0],
2218+
"super() can't find self"); // really a TypeError
2219+
return;
2220+
}
2221+
2222+
// a super() call
2223+
EMIT_ARG(call_function, 2, 0, 0);
2224+
i = 1;
2225+
}
2226+
2227+
// compile the remaining trailers
2228+
for (; i < num_trail; i++) {
2229+
if (i + 1 < num_trail
2230+
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[i]) == PN_trailer_period
2231+
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[i + 1]) == PN_trailer_paren) {
2232+
// optimisation for method calls a.f(...), following PyPy
2233+
mp_parse_node_struct_t *pns_period = pns_trail[i];
2234+
mp_parse_node_struct_t *pns_paren = pns_trail[i + 1];
2235+
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]));
2236+
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
2237+
i += 1;
2238+
} else {
2239+
// node is one of: trailer_paren, trailer_bracket, trailer_period
2240+
compile_node(comp, (mp_parse_node_t)pns_trail[i]);
2241+
}
22072242
}
2243+
}
2244+
2245+
STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
2246+
compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power
2247+
EMIT_ARG(binary_op, MP_BINARY_OP_POWER);
2248+
}
2249+
2250+
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {
2251+
// function to call is on top of stack
22082252

22092253
// get the list of arguments
22102254
mp_parse_node_t *args;
@@ -2285,23 +2329,6 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
22852329
}
22862330
}
22872331

2288-
STATIC void compile_atom_expr_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) {
2289-
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
2290-
for (int i = 0; i < num_nodes; i++) {
2291-
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)) {
2292-
// optimisation for method calls a.f(...), following PyPy
2293-
mp_parse_node_struct_t *pns_period = (mp_parse_node_struct_t*)pns->nodes[i];
2294-
mp_parse_node_struct_t *pns_paren = (mp_parse_node_struct_t*)pns->nodes[i + 1];
2295-
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0])); // get the method
2296-
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
2297-
i += 1;
2298-
} else {
2299-
compile_node(comp, pns->nodes[i]);
2300-
}
2301-
comp->func_arg_is_super = false;
2302-
}
2303-
}
2304-
23052332
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
23062333
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
23072334
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);

py/grammar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom),
261261
DEF_RULE_NC(atom_expr, or(1), rule(atom_expr_normal))
262262
#endif
263263
DEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers))
264-
DEF_RULE(atom_expr_trailers, c(atom_expr_trailers), one_or_more, rule(trailer))
264+
DEF_RULE_NC(atom_expr_trailers, one_or_more, rule(trailer))
265265
DEF_RULE_NC(power_dbl_star, and_ident(2), tok(OP_DBL_STAR), rule(factor))
266266

267267
// atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'

tests/cmdline/cmd_parsetree.py.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
tok(4)
44
[ 4] rule(22) (n=4)
55
id(i)
6-
[ 4] rule(45) (n=1)
6+
[ 4] rule(44) (n=1)
77
NULL
88
[ 5] rule(8) (n=0)
99
NULL

0 commit comments

Comments
 (0)