summaryrefslogtreecommitdiffstatshomepage
path: root/py/compile2.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/compile2.c')
-rw-r--r--py/compile2.c184
1 files changed, 129 insertions, 55 deletions
diff --git a/py/compile2.c b/py/compile2.c
index cdd3a0ccc2..f9636bd3c7 100644
--- a/py/compile2.c
+++ b/py/compile2.c
@@ -44,10 +44,19 @@
// TODO need to mangle __attr names
typedef enum {
+// define rules with a compile function
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
+#define DEF_RULE_NC(rule, kind, ...)
#include "py/grammar.h"
#undef DEF_RULE
- PN_maximum_number_of,
+#undef DEF_RULE_NC
+ PN_const_object, // special node for a constant, generic Python object
+// define rules without a compile function
+#define DEF_RULE(rule, comp, kind, ...)
+#define DEF_RULE_NC(rule, kind, ...) PN_##rule,
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
} pn_kind_t;
#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE
@@ -79,7 +88,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
@@ -751,7 +759,6 @@ STATIC qstr compile_classdef_helper(compiler_t *comp, const byte *p, uint emit_o
if (pt_is_rule(p_parents, PN_classdef_2)) {
p_parents = NULL;
}
- comp->func_arg_is_super = false;
compile_trailer_paren_helper(comp, p_parents, false, 2);
// return its name (the 'C' in class C(...):")
@@ -831,7 +838,6 @@ STATIC void compile_decorated(compiler_t *comp, const byte *p, const byte *ptop)
// nodes[1] contains arguments to the decorator function, if any
if (!pt_is_null_with_top(p, ptop_decorator)) {
// call the decorator function with the arguments in nodes[1]
- comp->func_arg_is_super = false;
compile_node(comp, p);
}
}
@@ -1498,6 +1504,10 @@ STATIC void compile_for_stmt(compiler_t *comp, const byte *p, const byte *ptop)
goto optimise_fail;
}
p_range_args = pt_get_small_int(p_range_args, &step);
+ // the step must be non-zero
+ if (step == 0) {
+ goto optimise_fail;
+ }
if (p_range_args != p_range_args_top) {
// range has at least 4 args, so don't know how to optimise it
goto optimise_fail;
@@ -1536,7 +1546,7 @@ optimise_fail:;
const byte *p_it = pt_next(p);
const byte *p_body = compile_node(comp, p_it); // iterator
- EMIT(get_iter);
+ EMIT_ARG(get_iter, true);
EMIT_ARG(label_assign, continue_label);
EMIT_ARG(for_iter, pop_label);
c_assign(comp, p, ASSIGN_STORE); // variable
@@ -2075,10 +2085,89 @@ STATIC void compile_factor_2(compiler_t *comp, const byte *p, const byte *ptop)
}
STATIC void compile_atom_expr_normal(compiler_t *comp, const byte *p, const byte *ptop) {
- // this is to handle special super() call
- comp->func_arg_is_super = pt_is_id(p, MP_QSTR_super);
+ const byte *p_start = p;
+
+ // compile the subject of the expression
+ p = compile_node(comp, p);
+
+ // get the array of trailers, it may be a single item or a list
+ if (pt_is_rule(p, PN_atom_expr_trailers)) {
+ p = pt_rule_extract_top(p, &ptop);
+ }
+
+ // handle special super() call
+ if (comp->scope_cur->kind == SCOPE_FUNCTION
+ && pt_is_id(p_start, MP_QSTR_super)
+ && pt_is_rule(p, PN_trailer_paren)
+ && pt_is_rule_empty(p)) {
+ // 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__);
- compile_generic_all_nodes(comp, p, ptop);
+ // 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, p,
+ "super() can't find self"); // really a TypeError
+ return;
+ }
+
+ if (pt_num_nodes(p, ptop) >= 3
+ && pt_is_rule(pt_next(p), PN_trailer_period)
+ && pt_is_rule(pt_next(pt_next(p)), PN_trailer_paren)) {
+ // optimisation for method calls super().f(...), to eliminate heap allocation
+ const byte *p_period = pt_next(p);
+ const byte *p_paren = pt_next(p_period);
+ qstr method_name;
+ pt_extract_id(pt_rule_first(p_period), &method_name);
+ EMIT_ARG(load_method, method_name, true);
+ if (pt_is_rule_empty(p_paren)) {
+ p_paren = NULL;
+ } else {
+ p_paren = pt_rule_first(p_paren);
+ }
+ compile_trailer_paren_helper(comp, p_paren, true, 0);
+ p = pt_next(p);
+ p = pt_next(p);
+ p = pt_next(p);
+ } else {
+ // a super() call
+ EMIT_ARG(call_function, 2, 0, 0);
+ p = pt_next(p);
+ }
+ }
+
+ while (p != ptop) {
+ const byte *p_next = pt_next(p);
+ if (p_next != ptop && pt_is_rule(p, PN_trailer_period) && pt_is_rule(p_next, PN_trailer_paren)) {
+ // optimisation for method calls a.f(...), following PyPy
+ const byte *p_period = pt_rule_first(p);
+ const byte *p_paren;
+ if (pt_is_rule_empty(p_next)) {
+ p_paren = NULL;
+ } else {
+ p_paren = pt_rule_first(p_next);
+ }
+ qstr method_name;
+ pt_extract_id(p_period, &method_name);
+ EMIT_ARG(load_method, method_name, false);
+ compile_trailer_paren_helper(comp, p_paren, true, 0);
+ p = pt_next(p_next);
+ } else {
+ // node is one of: trailer_paren, trailer_bracket, trailer_period
+ p = compile_node(comp, p);
+ }
+ }
}
STATIC void compile_power(compiler_t *comp, const byte *p, const byte *ptop) {
@@ -2090,22 +2179,6 @@ STATIC void compile_power(compiler_t *comp, const byte *p, const byte *ptop) {
STATIC void compile_trailer_paren_helper(compiler_t *comp, const byte *p_arglist, bool is_method_call, int n_positional_extra) {
// function to call is on top of stack
- // this is to handle special super() call
- if (p_arglist == NULL && 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++) {
- if (comp->scope_cur->id_info[i].flags & ID_FLAG_IS_PARAM) {
- // first argument found; load it and call super
- EMIT_LOAD_FAST(MP_QSTR_, comp->scope_cur->id_info[i].local_num);
- EMIT_ARG(call_function, 2, 0, 0);
- return;
- }
- }
- compile_syntax_error(comp, NULL, "super() call cannot find self"); // really a TypeError
- return;
- }
-
// get the list of arguments
const byte *ptop;
if (p_arglist == NULL) {
@@ -2192,30 +2265,6 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, const byte *p_arglist
}
}
-STATIC void compile_atom_expr_trailers(compiler_t *comp, const byte *p, const byte *ptop) {
- while (p != ptop) {
- const byte *p_next = pt_next(p);
- if (p_next != ptop && pt_is_rule(p, PN_trailer_period) && pt_is_rule(p_next, PN_trailer_paren)) {
- // optimisation for method calls a.f(...), following PyPy
- const byte *p_period = pt_rule_first(p);
- const byte *p_paren;
- if (pt_is_rule_empty(p_next)) {
- p_paren = NULL;
- } else {
- p_paren = pt_rule_first(p_next);
- }
- qstr method_name;
- pt_extract_id(p_period, &method_name);
- EMIT_ARG(load_method, method_name);
- compile_trailer_paren_helper(comp, p_paren, true, 0);
- p = pt_next(p_next);
- } else {
- p = compile_node(comp, p);
- }
- comp->func_arg_is_super = false;
- }
-}
-
// p needs to point to 2 successive nodes, first is lhs of comprehension, second is PN_comp_for node
STATIC void compile_comprehension(compiler_t *comp, const byte *p, scope_kind_t kind) {
const byte *p_comp_for = pt_next(p);
@@ -2237,7 +2286,9 @@ STATIC void compile_comprehension(compiler_t *comp, const byte *p, scope_kind_t
close_over_variables_etc(comp, this_scope, 0, 0);
compile_node(comp, pt_next(p_comp_for)); // source of the iterator
- EMIT(get_iter);
+ if (kind == SCOPE_GEN_EXPR) {
+ EMIT_ARG(get_iter, false);
+ }
EMIT_ARG(call_function, 1, 0, 0);
}
@@ -2471,7 +2522,7 @@ STATIC void compile_yield_expr(compiler_t *comp, const byte *p, const byte *ptop
} else if (pt_is_rule(p, PN_yield_arg_from)) {
p = pt_rule_first(p);
compile_node(comp, p);
- EMIT(get_iter);
+ EMIT_ARG(get_iter, false);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
EMIT(yield_from);
} else {
@@ -2480,16 +2531,27 @@ STATIC void compile_yield_expr(compiler_t *comp, const byte *p, const byte *ptop
}
}
+STATIC mp_obj_t get_const_object(compiler_t *comp, const byte *p) {
+ size_t idx;
+ p = pt_extract_const_obj(p, &idx);
+ return (mp_obj_t)comp->co_data[idx];
+}
+
+STATIC void compile_const_object(compiler_t *comp, const byte *p, const byte *ptop) {
+ EMIT_ARG(load_const_obj, get_const_object(comp, p));
+}
+
typedef void (*compile_function_t)(compiler_t*, const byte*, const byte*);
STATIC compile_function_t compile_function[] = {
#define nc NULL
#define c(f) compile_##f
#define DEF_RULE(rule, comp, kind, ...) comp,
+#define DEF_RULE_NC(rule, kind, ...)
#include "py/grammar.h"
-#undef nc
#undef c
#undef DEF_RULE
- NULL,
+#undef DEF_RULE_NC
+ compile_const_object,
};
STATIC const byte *compile_node(compiler_t *comp, const byte *p) {
@@ -2712,7 +2774,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, const byte *p_comp_for, co
EMIT(yield_value);
EMIT(pop_top);
} else {
- EMIT_ARG(store_comp, comp->scope_cur->kind, for_depth + 2);
+ EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5);
}
} else if (pt_is_rule(p_iter, PN_comp_if)) {
// if condition
@@ -2726,7 +2788,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, const byte *p_comp_for, co
const byte *p0 = pt_rule_extract_top(p_iter, &ptop);
p0 = pt_next(p0); // skip scope index
compile_node(comp, pt_next(p0));
- EMIT(get_iter);
+ EMIT_ARG(get_iter, true);
compile_scope_comp_iter(comp, p0, ptop, p_inner_expr, for_depth + 1);
}
@@ -2899,7 +2961,19 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
#endif
}
- compile_load_id(comp, qstr_arg);
+ // There are 4 slots on the stack for the iterator, and the first one is
+ // NULL to indicate that the second one points to the iterator object.
+ if (scope->kind == SCOPE_GEN_EXPR) {
+ // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4
+ EMIT(load_null);
+ compile_load_id(comp, qstr_arg);
+ EMIT(load_null);
+ EMIT(load_null);
+ } else {
+ compile_load_id(comp, qstr_arg);
+ EMIT_ARG(get_iter, true);
+ }
+
compile_scope_comp_iter(comp, p_comp_for, p_comp_for_top, p, 0);
if (scope->kind == SCOPE_GEN_EXPR) {