summaryrefslogtreecommitdiff
path: root/py/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/parse.c')
-rw-r--r--py/parse.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/py/parse.c b/py/parse.c
index 8f0a25cf2..b8a40f4bb 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -291,6 +291,16 @@ STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) {
return ret;
}
+#if MICROPY_COMP_CONST_TUPLE
+STATIC void parser_free_parse_node_struct(parser_t *parser, mp_parse_node_struct_t *pns) {
+ mp_parse_chunk_t *chunk = parser->cur_chunk;
+ if (chunk->data <= (byte *)pns && (byte *)pns < chunk->data + chunk->union_.used) {
+ size_t num_bytes = sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
+ chunk->union_.used -= num_bytes;
+ }
+}
+#endif
+
STATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) {
if (parser->rule_stack_top >= parser->rule_stack_alloc) {
rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC);
@@ -317,6 +327,13 @@ STATIC uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) {
return rule_id;
}
+#if MICROPY_COMP_CONST_TUPLE
+STATIC uint8_t peek_rule(parser_t *parser, size_t n) {
+ assert(parser->rule_stack_top > n);
+ return parser->rule_stack[parser->rule_stack_top - 1 - n].rule_id;
+}
+#endif
+
bool mp_parse_node_is_const_false(mp_parse_node_t pn) {
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE)
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
@@ -340,6 +357,76 @@ bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) {
}
}
+#if MICROPY_COMP_CONST_TUPLE
+STATIC bool mp_parse_node_is_const(mp_parse_node_t pn) {
+ if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
+ // Small integer.
+ return true;
+ } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
+ // Possible str, or constant literal.
+ uintptr_t kind = MP_PARSE_NODE_LEAF_KIND(pn);
+ if (kind == MP_PARSE_NODE_STRING) {
+ return true;
+ } else if (kind == MP_PARSE_NODE_TOKEN) {
+ uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
+ return arg == MP_TOKEN_KW_NONE
+ || arg == MP_TOKEN_KW_FALSE
+ || arg == MP_TOKEN_KW_TRUE
+ || arg == MP_TOKEN_ELLIPSIS;
+ }
+ } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) {
+ // Constant object.
+ return true;
+ } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_atom_paren)) {
+ // Possible empty tuple.
+ mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
+ return MP_PARSE_NODE_IS_NULL(pns->nodes[0]);
+ }
+ return false;
+}
+
+STATIC mp_obj_t mp_parse_node_convert_to_obj(mp_parse_node_t pn) {
+ assert(mp_parse_node_is_const(pn));
+ if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
+ mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
+ #if MICROPY_DYNAMIC_COMPILER
+ mp_uint_t sign_mask = -((mp_uint_t)1 << (mp_dynamic_compiler.small_int_bits - 1));
+ if (!((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask)) {
+ // Integer doesn't fit in a small-int, so create a multi-precision int object.
+ return mp_obj_new_int_from_ll(arg);
+ }
+ #endif
+ return MP_OBJ_NEW_SMALL_INT(arg);
+ } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
+ uintptr_t kind = MP_PARSE_NODE_LEAF_KIND(pn);
+ uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
+ if (kind == MP_PARSE_NODE_STRING) {
+ return MP_OBJ_NEW_QSTR(arg);
+ } else {
+ assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN);
+ switch (arg) {
+ case MP_TOKEN_KW_NONE:
+ return mp_const_none;
+ case MP_TOKEN_KW_FALSE:
+ return mp_const_false;
+ case MP_TOKEN_KW_TRUE:
+ return mp_const_true;
+ default:
+ assert(arg == MP_TOKEN_ELLIPSIS);
+ return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj);
+ }
+ }
+ } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) {
+ mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
+ return mp_parse_node_extract_const_object(pns);
+ } else {
+ assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_atom_paren));
+ assert(MP_PARSE_NODE_IS_NULL(((mp_parse_node_struct_t *)pn)->nodes[0]));
+ return mp_const_empty_tuple;
+ }
+}
+#endif
+
size_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes) {
if (MP_PARSE_NODE_IS_NULL(*pn)) {
*nodes = NULL;
@@ -791,6 +878,59 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
}
#endif
+#if MICROPY_COMP_CONST_TUPLE
+STATIC bool build_tuple_from_stack(parser_t *parser, size_t src_line, size_t num_args) {
+ for (size_t i = num_args; i > 0;) {
+ mp_parse_node_t pn = peek_result(parser, --i);
+ if (!mp_parse_node_is_const(pn)) {
+ return false;
+ }
+ }
+ mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_args, NULL));
+ for (size_t i = num_args; i > 0;) {
+ mp_parse_node_t pn = pop_result(parser);
+ tuple->items[--i] = mp_parse_node_convert_to_obj(pn);
+ if (MP_PARSE_NODE_IS_STRUCT(pn)) {
+ parser_free_parse_node_struct(parser, (mp_parse_node_struct_t *)pn);
+ }
+ }
+ push_result_node(parser, make_node_const_object(parser, src_line, MP_OBJ_FROM_PTR(tuple)));
+ return true;
+}
+
+STATIC bool build_tuple(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
+ if (rule_id == RULE_testlist_comp) {
+ if (peek_rule(parser, 0) == RULE_atom_paren) {
+ // Tuple of the form "(a,)".
+ return build_tuple_from_stack(parser, src_line, num_args);
+ }
+ }
+ if (rule_id == RULE_testlist_comp_3c) {
+ assert(peek_rule(parser, 0) == RULE_testlist_comp_3b);
+ assert(peek_rule(parser, 1) == RULE_testlist_comp);
+ if (peek_rule(parser, 2) == RULE_atom_paren) {
+ // Tuple of the form "(a, b)".
+ if (build_tuple_from_stack(parser, src_line, num_args)) {
+ parser->rule_stack_top -= 2; // discard 2 rules
+ return true;
+ }
+ }
+ }
+ if (rule_id == RULE_testlist_star_expr
+ || rule_id == RULE_testlist
+ || rule_id == RULE_subscriptlist) {
+ // Tuple of the form:
+ // - x = a, b
+ // - return a, b
+ // - for x in a, b: pass
+ // - x[a, b]
+ return build_tuple_from_stack(parser, src_line, num_args);
+ }
+
+ return false;
+}
+#endif
+
STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
// Simplify and optimise certain rules, to reduce memory usage and simplify the compiler.
if (rule_id == RULE_atom_paren) {
@@ -847,6 +987,13 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
}
#endif
+ #if MICROPY_COMP_CONST_TUPLE
+ if (build_tuple(parser, src_line, rule_id, num_args)) {
+ // we built a tuple from this rule so return straightaway
+ return;
+ }
+ #endif
+
mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args);
pn->source_line = src_line;
pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);