if (strcmp(STR(n), "in") == 0) return In; if (strcmp(STR(n), "is") == 0) return Is; default: PyErr_Format(PyExc_SystemError, "invalid comp_op: %s", STR(n)); return (cmpop_ty)0; } } else if (NCH(n) == 2) { /* handle "not in" and "is not" */ switch (TYPE(CHILD(n, 0))) { case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0) return NotIn; if (strcmp(STR(CHILD(n, 0)), "is") == 0) return IsNot; default: PyErr_Format(PyExc_SystemError, "invalid comp_op: %s %s", STR(CHILD(n, 0)), STR(CHILD(n, 1))); return (cmpop_ty)0; } } PyErr_Format(PyExc_SystemError, "invalid comp_op: has %d children", NCH(n)); return (cmpop_ty)0;} static asdl_seq *seq_for_testlist(struct compiling *c, const node *n){ /* testlist: test (',' test)* [','] */ asdl_seq *seq; expr_ty expression; int i; assert(TYPE(n) == testlist || TYPE(n) == listmaker || TYPE(n) == testlist_gexp || TYPE(n) == testlist_safe || TYPE(n) == testlist1 ); seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); if (!seq) return NULL; for (i = 0; i < NCH(n); i += 2) { assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test); expression = ast_for_expr(c, CHILD(n, i)); if (!expression) return NULL; assert(i / 2 < seq->size); asdl_seq_SET(seq, i / 2, expression); } return seq;} static expr_tycompiler_complex_args(struct compiling *c, const node *n){ int i, len = (NCH(n) + 1) / 2; expr_ty result; asdl_seq *args = asdl_seq_new(len, c->c_arena); if (!args) return NULL; /* fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] */ REQ(n, fplist); for (i = 0; i < len; i++) { const node *fpdef_node = CHILD(n, 2*i); const node *child; expr_ty arg;set_name: /* fpdef_node is either a NAME or an fplist */ child = CHILD(fpdef_node, 0); if (TYPE(child) == NAME) { if (!strcmp(STR(child), "None")) { ast_error(child, "assignment to None"); return NULL; } arg = Name(NEW_IDENTIFIER(child), Store, LINENO(child), child->n_col_offset, c->c_arena); } else { assert(TYPE(fpdef_node) == fpdef); /* fpdef_node[0] is not a name, so it must be a '(', get CHILD[1] */ child = CHILD(fpdef_node, 1); assert(TYPE(child) == fplist); /* NCH == 1 means we have (x), we need to elide the extra parens */ if (NCH(child) == 1) { fpdef_node = CHILD(child, 0); assert(TYPE(fpdef_node) == fpdef); goto set_name; } arg = compiler_complex_args(c, child); } asdl_seq_SET(args, i, arg); } result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); if (!set_context(result, Store, n)) return NULL; return result;} /* Create AST for argument list. */ static arguments_tyast_for_arguments(struct compiling *c, const node *n){ /* parameters: '(' [varargslist] ')' varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] */ int i, j, k, n_args = 0, n_defaults = 0, found_default = 0; asdl_seq *args, *defaults; identifier vararg = NULL, kwarg = NULL; node *ch; if (TYPE(n) == parameters) { if (NCH(n) == 2) /* () as argument list */ return arguments(NULL, NULL, NULL, NULL, c->c_arena); n = CHILD(n, 1); } REQ(n, varargslist); /* first count the number of normal args & defaults */ for (i = 0; i < NCH(n); i++) { ch = CHILD(n, i); if (TYPE(ch) == fpdef) n_args++; if (TYPE(ch) == EQUAL) n_defaults++; } args = (n_args ? asdl_seq_new(n_args, c->c_arena) : NULL); if (!args && n_args) return NULL; /* Don't need to goto error; no objects allocated */ defaults = (n_defaults ? asdl_seq_new(n_defaults, c->c_arena) : NULL); if (!defaults && n_defaults) return NULL; /* Don't need to goto error; no objects allocated */ /* fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] */ i = 0; j = 0; /* index for defaults */ k = 0; /* index for args */ while (i < NCH(n)) { ch = CHILD(n, i); switch (TYPE(ch)) { case fpdef: handle_fpdef: /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is anything other than EQUAL or a comma? */ /* XXX Should NCH(n) check be made a separate check? */ if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) { expr_ty expression = ast_for_expr(c, CHILD(n, i + 2)); if (!expression) goto error; assert(defaults != NULL); asdl_seq_SET(defaults, j++, expression); i += 2; found_default = 1; } else if (found_default) { ast_error(n, "non-default argument follows default argument"); goto error; } if (NCH(ch) == 3) { ch = CHILD(ch, 1); /* def foo((x)): is not complex, special case. */ if (NCH(ch) != 1) { /* We have complex arguments, setup for unpacking. */ asdl_seq_SET(args, k++, compiler_complex_args(c, ch)); } else { /* def foo((x)): setup for checking NAME below. */ /* Loop because there can be many parens and tuple upacking mixed in. */ ch = CHILD(ch, 0); assert(TYPE(ch) == fpdef); goto handle_fpdef; } } if (TYPE(CHILD(ch, 0)) == NAME) { expr_ty name; if (!strcmp(STR(CHILD(ch, 0)), "None")) { ast_error(CHILD(ch, 0), "assignment to None"); goto error; } name = Name(NEW_IDENTIFIER(CHILD(ch, 0)), Param, LINENO(ch), ch->n_col_offset, c->c_arena); if (!name) goto error; asdl_seq_SET(args, k++, name); } i += 2; /* the name and the comma */ break; case STAR: if (!strcmp(STR(CHILD(n, i+1)), "None")) { ast_error(CHILD(n, i+1), "assignment to None"); goto error; } vararg = NEW_IDENTIFIER(CHILD(n, i+1)); i += 3; break; case DOUBLESTAR: if (!strcmp(STR(CHILD(n, i+1)), "None")) { ast_error(CHILD(n, i+1), "assignment to None"); goto error; } kwarg = NEW_IDENTIFIER(CHILD(n, i+1)); i += 3; break; default: PyErr_Format(PyExc_SystemError, "unexpected node in varargslist: %d @ %d", TYPE(ch), i); goto error; } } return arguments(args, vararg, kwarg, defaults, c->c_arena); error: Py_XDECREF(vararg); Py_XDECREF(kwarg); return NULL;} static expr_tyast_for_dotted_name(struct compiling *c, const node *n){ expr_ty e; identifier id; int lineno, col_offset; int i; REQ(n, dotted_name); lineno = LINENO(n); col_offset = n->n_col_offset; id = NEW_IDENTIFIER(CHILD(n, 0)); if (!id) return NULL; e = Name(id, Load, lineno, col_offset, c->c_arena); if (!e) return NULL; for (i = 2; i < NCH(n); i+=2) { id = NEW_IDENTIFIER(CHILD(n, i)); if (!id) return NULL; e = Attribute(e, id, Load, lineno, col_offset, c->c_arena); if (!e) return NULL; } return e;} static expr_tyast_for_decorator(struct compiling *c, const node *n){ /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */ expr_ty d = NULL; expr_ty name_expr; REQ(n, decorator); REQ(CHILD(n, 0), AT); REQ(RCHILD(n, -1), NEWLINE); name_expr = ast_for_dotted_name(c, CHILD(n, 1)); if (!name_expr) return NULL; if (NCH(n) == 3) { /* No arguments */ d = name_expr; name_expr = NULL; } else if (NCH(n) == 5) { /* Call with no arguments */ d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); if (!d) return NULL; name_expr = NULL; } else { d = ast_for_call(c, CHILD(n, 3), name_expr); if (!d) return NULL; name_expr = NULL; } return d;} static asdl_seq*ast_for_decorators(struct compiling *c, const node *n){ asdl_seq* decorator_seq; expr_ty d; int i; REQ(n, decorators); decorator_seq = asdl_seq_new(NCH(n), c->c_arena); if (!decorator_seq) return NULL; for (i = 0; i < NCH(n); i++) { d = ast_for_decorator(c, CHILD(n, i)); if (!d) return NULL; asdl_seq_SET(decorator_seq, i, d); } return decorator_seq;} static stmt_tyast_for_funcdef(struct compiling *c, const node *n){ /* funcdef: 'def' [decorators] NAME parameters ':' suite */ identifier name; arguments_ty args; asdl_seq *body; asdl_seq *decorator_seq = NULL; int name_i; REQ(n, funcdef); if (NCH(n) == 6) { /* decorators are present */ decorator_seq = ast_for_decorators(c, CHILD(n, 0)); if (!decorator_seq) return NULL; name_i = 2; } else { name_i = 1; } name = NEW_IDENTIFIER(CHILD(n, name_i)); if (!name) return NULL; else if (!strcmp(STR(CHILD(n, name_i)), "None")) { ast_error(CHILD(n, name_i), "assignment to None"); return NULL; } args = ast_for_arguments(c, CHILD(n, name_i + 1)); if (!args) return NULL; body = ast_for_suite(c, CHILD(n, name_i + 3)); if (!body) return NULL; return FunctionDef(name, args, body, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena);} static expr_tyast_for_lambdef(struct compiling *c, const node *n){ /* lambdef: 'lambda' [varargslist] ':' test */ arguments_ty args; expr_ty expression; if (NCH(n) == 3) { args = arguments(NULL, NULL, NULL, NULL, c->c_arena); if (!args) return NULL; expression = ast_for_expr(c, CHILD(n, 2)); if (!expression) return NULL; } else { args = ast_for_arguments(c, CHILD(n, 1)); if (!args) return NULL; expression = ast_for_expr(c, CHILD(n, 3)); if (!expression) return NULL; } return Lambda(args, expression, LINENO(n), n->n_col_offset, c->c_arena);} static expr_tyast_for_ifexpr(struct compiling *c, const node *n){ /* test: or_test 'if' or_test 'else' test */ expr_ty expression, body, orelse; assert(NCH(n) == 5); body = ast_for_expr(c, CHILD(n, 0)); if (!body) return NULL; expression = ast_for_expr(c, CHILD(n, 2)); if (!expression) return NULL; orelse = ast_for_expr(c, CHILD(n, 4)); if (!orelse) return NULL; return IfExp(expression, body, orelse, LINENO(n), n->n_col_offset, c->c_arena);} /* Count the number of 'for' loop in a list comprehension. Helper for ast_for_listcomp().*/ static intcount_list_fors(const node *n){ int n_fors = 0; node *ch = CHILD(n, 1); count_list_for: n_fors++; REQ(ch, list_for); if (NCH(ch) == 5) ch = CHILD(ch, 4); else return n_fors; count_list_iter: REQ(ch, list_iter); ch = CHILD(ch, 0); if (TYPE(ch) == list_for) goto count_list_for; else if (TYPE(ch) == list_if) { if (NCH(ch) == 3) { ch = CHILD(ch, 2); goto count_list_iter; } else return n_fors; } /* Should never be reached */ PyErr_SetString(PyExc_SystemError, "logic error in count_list_fors"); return -1;} /* Count the number of 'if' statements in a list comprehension. Helper for ast_for_listcomp().*/ static intcount_list_ifs(const node *n){ int n_ifs = 0; count_list_iter: REQ(n, list_iter); if (TYPE(CHILD(n, 0)) == list_for) return n_ifs; n = CHILD(n, 0); REQ(n, list_if); n_ifs++; if (NCH(n) == 2) return n_ifs; n = CHILD(n, 2); goto count_list_iter;} static expr_tyast_for_listcomp(struct compiling *c, const node *n){ /* listmaker: test ( list_for | (',' test)* [','] ) list_for: 'for' exprlist 'in' testlist_safe [list_iter] list_iter: list_for | list_if list_if: 'if' test [list_iter] testlist_safe: test [(',' test)+ [',']] */ expr_ty elt; asdl_seq *listcomps; int i, n_fors; node *ch; REQ(n, listmaker); assert(NCH(n) > 1); elt = ast_for_expr(c, CHILD(n, 0)); if (!elt) return NULL; n_fors = count_list_fors(n); if (n_fors == -1) return NULL; listcomps = asdl_seq_new(n_fors, c->c_arena);Lines 501–1000 of 3292. Previous lines Load more
if (strcmp(STR(n), "in") == 0) return In; if (strcmp(STR(n), "is") == 0) return Is; default: PyErr_Format(PyExc_SystemError, "invalid comp_op: %s", STR(n)); return (cmpop_ty)0; } } else if (NCH(n) == 2) { /* handle "not in" and "is not" */ switch (TYPE(CHILD(n, 0))) { case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0) return NotIn; if (strcmp(STR(CHILD(n, 0)), "is") == 0) return IsNot; default: PyErr_Format(PyExc_SystemError, "invalid comp_op: %s %s", STR(CHILD(n, 0)), STR(CHILD(n, 1))); return (cmpop_ty)0; } } PyErr_Format(PyExc_SystemError, "invalid comp_op: has %d children", NCH(n)); return (cmpop_ty)0; } static asdl_seq * seq_for_testlist(struct compiling *c, const node *n) { /* testlist: test (',' test)* [','] */ asdl_seq *seq; expr_ty expression; int i; assert(TYPE(n) == testlist || TYPE(n) == listmaker || TYPE(n) == testlist_gexp || TYPE(n) == testlist_safe || TYPE(n) == testlist1 ); seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); if (!seq) return NULL; for (i = 0; i < NCH(n); i += 2) { assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test); expression = ast_for_expr(c, CHILD(n, i)); if (!expression) return NULL; assert(i / 2 < seq->size); asdl_seq_SET(seq, i / 2, expression); } return seq; } static expr_ty compiler_complex_args(struct compiling *c, const node *n) { int i, len = (NCH(n) + 1) / 2; expr_ty result; asdl_seq *args = asdl_seq_new(len, c->c_arena); if (!args) return NULL; /* fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] */ REQ(n, fplist); for (i = 0; i < len; i++) { const node *fpdef_node = CHILD(n, 2*i); const node *child; expr_ty arg; set_name: /* fpdef_node is either a NAME or an fplist */ child = CHILD(fpdef_node, 0); if (TYPE(child) == NAME) { if (!strcmp(STR(child), "None")) { ast_error(child, "assignment to None"); return NULL; } arg = Name(NEW_IDENTIFIER(child), Store, LINENO(child), child->n_col_offset, c->c_arena); } else { assert(TYPE(fpdef_node) == fpdef); /* fpdef_node[0] is not a name, so it must be a '(', get CHILD[1] */ child = CHILD(fpdef_node, 1); assert(TYPE(child) == fplist); /* NCH == 1 means we have (x), we need to elide the extra parens */ if (NCH(child) == 1) { fpdef_node = CHILD(child, 0); assert(TYPE(fpdef_node) == fpdef); goto set_name; } arg = compiler_complex_args(c, child); } asdl_seq_SET(args, i, arg); } result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); if (!set_context(result, Store, n)) return NULL; return result; } /* Create AST for argument list. */ static arguments_ty ast_for_arguments(struct compiling *c, const node *n) { /* parameters: '(' [varargslist] ')' varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] */ int i, j, k, n_args = 0, n_defaults = 0, found_default = 0; asdl_seq *args, *defaults; identifier vararg = NULL, kwarg = NULL; node *ch; if (TYPE(n) == parameters) { if (NCH(n) == 2) /* () as argument list */ return arguments(NULL, NULL, NULL, NULL, c->c_arena); n = CHILD(n, 1); } REQ(n, varargslist); /* first count the number of normal args & defaults */ for (i = 0; i < NCH(n); i++) { ch = CHILD(n, i); if (TYPE(ch) == fpdef) n_args++; if (TYPE(ch) == EQUAL) n_defaults++; } args = (n_args ? asdl_seq_new(n_args, c->c_arena) : NULL); if (!args && n_args) return NULL; /* Don't need to goto error; no objects allocated */ defaults = (n_defaults ? asdl_seq_new(n_defaults, c->c_arena) : NULL); if (!defaults && n_defaults) return NULL; /* Don't need to goto error; no objects allocated */ /* fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] */ i = 0; j = 0; /* index for defaults */ k = 0; /* index for args */ while (i < NCH(n)) { ch = CHILD(n, i); switch (TYPE(ch)) { case fpdef: handle_fpdef: /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is anything other than EQUAL or a comma? */ /* XXX Should NCH(n) check be made a separate check? */ if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) { expr_ty expression = ast_for_expr(c, CHILD(n, i + 2)); if (!expression) goto error; assert(defaults != NULL); asdl_seq_SET(defaults, j++, expression); i += 2; found_default = 1; } else if (found_default) { ast_error(n, "non-default argument follows default argument"); goto error; } if (NCH(ch) == 3) { ch = CHILD(ch, 1); /* def foo((x)): is not complex, special case. */ if (NCH(ch) != 1) { /* We have complex arguments, setup for unpacking. */ asdl_seq_SET(args, k++, compiler_complex_args(c, ch)); } else { /* def foo((x)): setup for checking NAME below. */ /* Loop because there can be many parens and tuple upacking mixed in. */ ch = CHILD(ch, 0); assert(TYPE(ch) == fpdef); goto handle_fpdef; } } if (TYPE(CHILD(ch, 0)) == NAME) { expr_ty name; if (!strcmp(STR(CHILD(ch, 0)), "None")) { ast_error(CHILD(ch, 0), "assignment to None"); goto error; } name = Name(NEW_IDENTIFIER(CHILD(ch, 0)), Param, LINENO(ch), ch->n_col_offset, c->c_arena); if (!name) goto error; asdl_seq_SET(args, k++, name); } i += 2; /* the name and the comma */ break; case STAR: if (!strcmp(STR(CHILD(n, i+1)), "None")) { ast_error(CHILD(n, i+1), "assignment to None"); goto error; } vararg = NEW_IDENTIFIER(CHILD(n, i+1)); i += 3; break; case DOUBLESTAR: if (!strcmp(STR(CHILD(n, i+1)), "None")) { ast_error(CHILD(n, i+1), "assignment to None"); goto error; } kwarg = NEW_IDENTIFIER(CHILD(n, i+1)); i += 3; break; default: PyErr_Format(PyExc_SystemError, "unexpected node in varargslist: %d @ %d", TYPE(ch), i); goto error; } } return arguments(args, vararg, kwarg, defaults, c->c_arena); error: Py_XDECREF(vararg); Py_XDECREF(kwarg); return NULL; } static expr_ty ast_for_dotted_name(struct compiling *c, const node *n) { expr_ty e; identifier id; int lineno, col_offset; int i; REQ(n, dotted_name); lineno = LINENO(n); col_offset = n->n_col_offset; id = NEW_IDENTIFIER(CHILD(n, 0)); if (!id) return NULL; e = Name(id, Load, lineno, col_offset, c->c_arena); if (!e) return NULL; for (i = 2; i < NCH(n); i+=2) { id = NEW_IDENTIFIER(CHILD(n, i)); if (!id) return NULL; e = Attribute(e, id, Load, lineno, col_offset, c->c_arena); if (!e) return NULL; } return e; } static expr_ty ast_for_decorator(struct compiling *c, const node *n) { /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */ expr_ty d = NULL; expr_ty name_expr; REQ(n, decorator); REQ(CHILD(n, 0), AT); REQ(RCHILD(n, -1), NEWLINE); name_expr = ast_for_dotted_name(c, CHILD(n, 1)); if (!name_expr) return NULL; if (NCH(n) == 3) { /* No arguments */ d = name_expr; name_expr = NULL; } else if (NCH(n) == 5) { /* Call with no arguments */ d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); if (!d) return NULL; name_expr = NULL; } else { d = ast_for_call(c, CHILD(n, 3), name_expr); if (!d) return NULL; name_expr = NULL; } return d; } static asdl_seq* ast_for_decorators(struct compiling *c, const node *n) { asdl_seq* decorator_seq; expr_ty d; int i; REQ(n, decorators); decorator_seq = asdl_seq_new(NCH(n), c->c_arena); if (!decorator_seq) return NULL; for (i = 0; i < NCH(n); i++) { d = ast_for_decorator(c, CHILD(n, i)); if (!d) return NULL; asdl_seq_SET(decorator_seq, i, d); } return decorator_seq; } static stmt_ty ast_for_funcdef(struct compiling *c, const node *n) { /* funcdef: 'def' [decorators] NAME parameters ':' suite */ identifier name; arguments_ty args; asdl_seq *body; asdl_seq *decorator_seq = NULL; int name_i; REQ(n, funcdef); if (NCH(n) == 6) { /* decorators are present */ decorator_seq = ast_for_decorators(c, CHILD(n, 0)); if (!decorator_seq) return NULL; name_i = 2; } else { name_i = 1; } name = NEW_IDENTIFIER(CHILD(n, name_i)); if (!name) return NULL; else if (!strcmp(STR(CHILD(n, name_i)), "None")) { ast_error(CHILD(n, name_i), "assignment to None"); return NULL; } args = ast_for_arguments(c, CHILD(n, name_i + 1)); if (!args) return NULL; body = ast_for_suite(c, CHILD(n, name_i + 3)); if (!body) return NULL; return FunctionDef(name, args, body, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } static expr_ty ast_for_lambdef(struct compiling *c, const node *n) { /* lambdef: 'lambda' [varargslist] ':' test */ arguments_ty args; expr_ty expression; if (NCH(n) == 3) { args = arguments(NULL, NULL, NULL, NULL, c->c_arena); if (!args) return NULL; expression = ast_for_expr(c, CHILD(n, 2)); if (!expression) return NULL; } else { args = ast_for_arguments(c, CHILD(n, 1)); if (!args) return NULL; expression = ast_for_expr(c, CHILD(n, 3)); if (!expression) return NULL; } return Lambda(args, expression, LINENO(n), n->n_col_offset, c->c_arena); } static expr_ty ast_for_ifexpr(struct compiling *c, const node *n) { /* test: or_test 'if' or_test 'else' test */ expr_ty expression, body, orelse; assert(NCH(n) == 5); body = ast_for_expr(c, CHILD(n, 0)); if (!body) return NULL; expression = ast_for_expr(c, CHILD(n, 2)); if (!expression) return NULL; orelse = ast_for_expr(c, CHILD(n, 4)); if (!orelse) return NULL; return IfExp(expression, body, orelse, LINENO(n), n->n_col_offset, c->c_arena); } /* Count the number of 'for' loop in a list comprehension. Helper for ast_for_listcomp(). */ static int count_list_fors(const node *n) { int n_fors = 0; node *ch = CHILD(n, 1); count_list_for: n_fors++; REQ(ch, list_for); if (NCH(ch) == 5) ch = CHILD(ch, 4); else return n_fors; count_list_iter: REQ(ch, list_iter); ch = CHILD(ch, 0); if (TYPE(ch) == list_for) goto count_list_for; else if (TYPE(ch) == list_if) { if (NCH(ch) == 3) { ch = CHILD(ch, 2); goto count_list_iter; } else return n_fors; } /* Should never be reached */ PyErr_SetString(PyExc_SystemError, "logic error in count_list_fors"); return -1; } /* Count the number of 'if' statements in a list comprehension. Helper for ast_for_listcomp(). */ static int count_list_ifs(const node *n) { int n_ifs = 0; count_list_iter: REQ(n, list_iter); if (TYPE(CHILD(n, 0)) == list_for) return n_ifs; n = CHILD(n, 0); REQ(n, list_if); n_ifs++; if (NCH(n) == 2) return n_ifs; n = CHILD(n, 2); goto count_list_iter; } static expr_ty ast_for_listcomp(struct compiling *c, const node *n) { /* listmaker: test ( list_for | (',' test)* [','] ) list_for: 'for' exprlist 'in' testlist_safe [list_iter] list_iter: list_for | list_if list_if: 'if' test [list_iter] testlist_safe: test [(',' test)+ [',']] */ expr_ty elt; asdl_seq *listcomps; int i, n_fors; node *ch; REQ(n, listmaker); assert(NCH(n) > 1); elt = ast_for_expr(c, CHILD(n, 0)); if (!elt) return NULL; n_fors = count_list_fors(n); if (n_fors == -1) return NULL; listcomps = asdl_seq_new(n_fors, c->c_arena);