aboutsummaryrefslogtreecommitdiff
path: root/py/parse.c
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2021-03-23 12:48:35 +1100
committerDamien George <damien@micropython.org>2021-09-10 14:09:44 +1000
commite6850838cdc1a0e0fe8e735a03e7df46d0dcdd0e (patch)
tree75692c103ae9d3d70578d63eab64916635bf1d8a /py/parse.c
parent61b7c098b9a21311bbcec3b43c279ec9aada311b (diff)
py/parse: Simplify parse nodes representing a list.
This commit simplifies and optimises the parse tree in-memory representation of lists of expressions, for tuples and lists, and when tuples are used on the left-hand-side of assignments and within del statements. This reduces memory usage of the parse tree when such code is compiled, and also reduces the size of the compiler. For example, (1,) was previously the following parse tree: expr_stmt(5) (n=2) atom_paren(45) (n=1) testlist_comp(146) (n=2) int(1) testlist_comp_3b(149) (n=1) NULL NULL and with this commit is now: expr_stmt(5) (n=2) atom_paren(45) (n=1) testlist_comp(146) (n=1) int(1) NULL Similarly, (1, 2, 3) was previously: expr_stmt(5) (n=2) atom_paren(45) (n=1) testlist_comp(146) (n=2) int(1) testlist_comp_3c(150) (n=2) int(2) int(3) NULL and is now: expr_stmt(5) (n=2) atom_paren(45) (n=1) testlist_comp(146) (n=3) int(1) int(2) int(3) NULL Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'py/parse.c')
-rw-r--r--py/parse.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/py/parse.c b/py/parse.c
index ae3fa8ea6..68c761734 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -796,9 +796,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
#endif
STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
- // optimise away parenthesis around an expression if possible
+ // Simplify and optimise certain rules, to reduce memory usage and simplify the compiler.
if (rule_id == RULE_atom_paren) {
- // there should be just 1 arg for this rule
+ // Remove parenthesis around a single expression if possible.
+ // This atom_paren rule always has a single argument, and after this
+ // optimisation that argument is either NULL or testlist_comp.
mp_parse_node_t pn = peek_result(parser, 0);
if (MP_PARSE_NODE_IS_NULL(pn)) {
// need to keep parenthesis for ()
@@ -808,6 +810,34 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
// parenthesis around a single expression, so it's just the expression
return;
}
+ } else if (rule_id == RULE_testlist_comp) {
+ // The testlist_comp rule can be the sole argument to either atom_parent
+ // or atom_bracket, for (...) and [...] respectively.
+ assert(num_args == 2);
+ mp_parse_node_t pn = peek_result(parser, 0);
+ if (MP_PARSE_NODE_IS_STRUCT(pn)) {
+ mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
+ if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3b) {
+ // tuple of one item, with trailing comma
+ pop_result(parser);
+ --num_args;
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3c) {
+ // tuple of many items, convert testlist_comp_3c to testlist_comp
+ pop_result(parser);
+ assert(pn == peek_result(parser, 0));
+ pns->kind_num_nodes = rule_id | MP_PARSE_NODE_STRUCT_NUM_NODES(pns) << 8;
+ return;
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_comp_for) {
+ // generator expression
+ } else {
+ // tuple with 2 items
+ }
+ } else {
+ // tuple with 2 items
+ }
+ } else if (rule_id == RULE_testlist_comp_3c) {
+ // steal first arg of outer testlist_comp rule
+ ++num_args;
}
#if MICROPY_COMP_CONST_FOLDING
@@ -827,6 +857,10 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
for (size_t i = num_args; i > 0; i--) {
pn->nodes[i - 1] = pop_result(parser);
}
+ if (rule_id == RULE_testlist_comp_3c) {
+ // need to push something non-null to replace stolen first arg of testlist_comp
+ push_result_node(parser, (mp_parse_node_t)pn);
+ }
push_result_node(parser, (mp_parse_node_t)pn);
}