Commit 93b37262 authored by Damien George's avatar Damien George
Browse files

py/parse: Optimise away parse node that's just parenthesis around expr.

Before this patch, (x+y)*z would be parsed to a tree that contained a
redundant identity parse node corresponding to the parenthesis.  With
this patch such nodes are optimised away, which reduces memory
requirements for expressions with parenthesis, and simplifies the
compiler because it doesn't need to handle this identity case.

A parenthesis parse node is still needed for tuples.
parent 67f40fb2
...@@ -299,14 +299,12 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la ...@@ -299,14 +299,12 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
if (jump_if == false) { if (jump_if == false) {
EMIT_ARG(jump, label); EMIT_ARG(jump, label);
} }
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { } else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
// non-empty tuple, acts as true for the condition // non-empty tuple, acts as true for the condition
if (jump_if == true) { if (jump_if == true) {
EMIT_ARG(jump, label); EMIT_ARG(jump, label);
} }
} else {
// parenthesis around 1 item, is just that item
c_if_cond(comp, pns->nodes[0], jump_if, label);
} }
return; return;
} }
...@@ -420,7 +418,6 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num ...@@ -420,7 +418,6 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
// assigns top of stack to pn // assigns top of stack to pn
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
tail_recursion:
assert(!MP_PARSE_NODE_IS_NULL(pn)); assert(!MP_PARSE_NODE_IS_NULL(pn));
if (MP_PARSE_NODE_IS_LEAF(pn)) { if (MP_PARSE_NODE_IS_LEAF(pn)) {
if (MP_PARSE_NODE_IS_ID(pn)) { if (MP_PARSE_NODE_IS_ID(pn)) {
...@@ -462,16 +459,13 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ ...@@ -462,16 +459,13 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// empty tuple // empty tuple
goto cannot_assign; goto cannot_assign;
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { } else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
if (assign_kind != ASSIGN_STORE) { if (assign_kind != ASSIGN_STORE) {
goto bad_aug; goto bad_aug;
} }
pns = (mp_parse_node_struct_t*)pns->nodes[0]; pns = (mp_parse_node_struct_t*)pns->nodes[0];
goto testlist_comp; goto testlist_comp;
} else {
// parenthesis around 1 item, is just that item
pn = pns->nodes[0];
goto tail_recursion;
} }
break; break;
...@@ -885,7 +879,10 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { ...@@ -885,7 +879,10 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
} }
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) { } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {
pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; pn = ((mp_parse_node_struct_t*)pn)->nodes[0];
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp)) { if (MP_PARSE_NODE_IS_NULL(pn)) {
goto cannot_delete;
} else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp));
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
// TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp
...@@ -915,12 +912,9 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { ...@@ -915,12 +912,9 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
c_del_stmt(comp, pns->nodes[0]); c_del_stmt(comp, pns->nodes[0]);
c_del_stmt(comp, pns->nodes[1]); c_del_stmt(comp, pns->nodes[1]);
} }
} else {
// tuple with 1 element
c_del_stmt(comp, pn);
} }
} else { } else {
// TODO is there anything else to implement? // some arbitrary statment that we can't delete (eg del 1)
goto cannot_delete; goto cannot_delete;
} }
...@@ -2185,7 +2179,8 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { ...@@ -2185,7 +2179,8 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// an empty tuple // an empty tuple
c_tuple(comp, MP_PARSE_NODE_NULL, NULL); c_tuple(comp, MP_PARSE_NODE_NULL, NULL);
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { } else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
pns = (mp_parse_node_struct_t*)pns->nodes[0]; pns = (mp_parse_node_struct_t*)pns->nodes[0];
assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1])); assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1]));
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
...@@ -2209,9 +2204,6 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { ...@@ -2209,9 +2204,6 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
tuple_with_2_items: tuple_with_2_items:
c_tuple(comp, MP_PARSE_NODE_NULL, pns); c_tuple(comp, MP_PARSE_NODE_NULL, pns);
} }
} else {
// parenthesis around a single item, is just that item
compile_node(comp, pns->nodes[0]);
} }
} }
......
...@@ -647,6 +647,20 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args ...@@ -647,6 +647,20 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
#endif #endif
STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args) { STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args) {
// optimise away parenthesis around an expression if possible
if (rule->rule_id == RULE_atom_paren) {
// there should be just 1 arg for this rule
mp_parse_node_t pn = peek_result(parser, 0);
if (MP_PARSE_NODE_IS_NULL(pn)) {
// need to keep parenthesis for ()
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_testlist_comp)) {
// need to keep parenthesis for (a, b, ...)
} else {
// parenthesis around a single expression, so it's just the expression
return;
}
}
#if MICROPY_COMP_CONST_FOLDING #if MICROPY_COMP_CONST_FOLDING
if (fold_constants(parser, rule, num_args)) { if (fold_constants(parser, rule, num_args)) {
// we folded this rule so return straight away // we folded this rule so return straight away
...@@ -864,8 +878,6 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { ...@@ -864,8 +878,6 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// if a rule has the RULE_ACT_ALLOW_IDENT bit set then this // if a rule has the RULE_ACT_ALLOW_IDENT bit set then this
// rule should not be emitted if it has only 1 argument // rule should not be emitted if it has only 1 argument
// NOTE: can't set this flag for atom_paren because we need it
// to distinguish, for example, [a,b] from [(a,b)]
if (rule->act & RULE_ACT_ALLOW_IDENT) { if (rule->act & RULE_ACT_ALLOW_IDENT) {
emit_rule = false; emit_rule = false;
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment