py/{parse2,compile2}: Update to work with merged master, v1.9.

Changes inclued:
- grammar.h now has DEF_RULE and DEF_RULE_NC
- iterators can be on the (Python) stack
- super() handling is refactored
- supe().foo(...) can be executed without the heap
This commit is contained in:
Damien George 2017-08-14 18:20:00 +10:00
parent 9624f10825
commit 3417b28eaf
2 changed files with 154 additions and 57 deletions

View File

@ -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_generic_all_nodes(comp, p, ptop);
// 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__);
// 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) {

View File

@ -65,10 +65,20 @@ typedef struct _rule_t {
} rule_t;
enum {
// define rules with a compile function
#define DEF_RULE(rule, comp, kind, ...) RULE_##rule,
#define DEF_RULE_NC(rule, kind, ...)
#include "py/grammar.h"
#undef DEF_RULE
RULE_maximum_number_of,
#undef DEF_RULE_NC
RULE_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, ...) RULE_##rule,
#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
};
#define or(n) (RULE_ACT_OR | n)
@ -83,8 +93,10 @@ enum {
#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r)
#ifdef USE_RULE_NAME
#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } };
#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } };
#else
#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } };
#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } };
#endif
#include "py/grammar.h"
#undef or
@ -96,11 +108,23 @@ enum {
#undef opt_rule
#undef one_or_more
#undef DEF_RULE
#undef DEF_RULE_NC
STATIC const rule_t *rules[] = {
// define rules with a compile function
#define DEF_RULE(rule, comp, kind, ...) &rule_##rule,
#define DEF_RULE_NC(rule, kind, ...)
#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
NULL, // RULE_const_object
// define rules without a compile function
#define DEF_RULE(rule, comp, kind, ...)
#define DEF_RULE_NC(rule, kind, ...) &rule_##rule,
#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
};
typedef struct _rule_stack_t {
@ -170,7 +194,6 @@ STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, siz
STATIC void push_rule_from_arg(parser_t *parser, size_t arg) {
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
size_t rule_id = arg & RULE_ARG_ARG_MASK;
assert(rule_id < RULE_maximum_number_of);
push_rule(parser, parser->lexer->tok_line, rules[rule_id], 0, 0);
}