[Python-checkins] python/dist/src/Python compile.c, 2.301, 2.302 graminit.c, 2.34, 2.35 symtable.c, 2.11, 2.12

rhettinger at users.sourceforge.net rhettinger at users.sourceforge.net
Wed May 19 04:20:36 EDT 2004


Update of /cvsroot/python/python/dist/src/Python
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9770/Python

Modified Files:
	compile.c graminit.c symtable.c 
Log Message:
SF patch #872326:  Generator expression implementation
(Code contributed by Jiwon Seo.)

The documentation portion of the patch is being re-worked and will be
checked-in soon.  Likewise, PEP 289 will be updated to reflect Guido's
rationale for the design decisions on binding behavior (as described in
in his patch comments and in discussions on python-dev).

The test file, test_genexps.py, is written in doctest format and is
meant to exercise all aspects of the the patch.  Further additions are
welcome from everyone.  Please stress test this new feature as much as
possible before the alpha release.



Index: compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.301
retrieving revision 2.302
diff -C2 -d -r2.301 -r2.302
*** compile.c	22 Mar 2004 17:52:53 -0000	2.301
--- compile.c	19 May 2004 08:20:15 -0000	2.302
***************
*** 745,753 ****
--- 745,757 ----
  static int com_addname(struct compiling *, PyObject *);
  static void com_addopname(struct compiling *, int, node *);
+ static void com_test(struct compiling *c, node *n);
  static void com_list(struct compiling *, node *, int);
  static void com_list_iter(struct compiling *, node *, node *, char *);
+ static void com_gen_iter(struct compiling *, node *, node *);
  static int com_argdefs(struct compiling *, node *);
  static void com_assign(struct compiling *, node *, int, node *);
  static void com_assign_name(struct compiling *, node *, int);
+ static int com_make_closure(struct compiling *c, PyCodeObject *co);
+ 
  static PyCodeObject *icompile(node *, struct compiling *);
  static PyCodeObject *jcompile(node *, const char *, struct compiling *,
***************
*** 760,763 ****
--- 764,768 ----
  
  /* symtable operations */
+ static int symtable_lookup(struct symtable *st, char *name);
  static struct symtable *symtable_build(node *, PyFutureFeatures *,
  				       const char *filename);
***************
*** 778,782 ****
--- 783,790 ----
  static void symtable_assign(struct symtable *, node *, int);
  static void symtable_list_comprehension(struct symtable *, node *);
+ static void symtable_generator_expression(struct symtable *, node *);
  static void symtable_list_for(struct symtable *, node *);
+ static void symtable_gen_for(struct symtable *, node *, int);
+ static void symtable_gen_iter(struct symtable *, node *);
  
  static int symtable_update_free_vars(struct symtable *);
***************
*** 1590,1594 ****
  	int save_begin = c->c_begin;
  
! 	/* list_iter: for v in expr [list_iter] */
  	com_node(c, CHILD(n, 3)); /* expr */
  	com_addbyte(c, GET_ITER);
--- 1598,1602 ----
  	int save_begin = c->c_begin;
  
! 	/* list_for: for v in expr [list_iter] */
  	com_node(c, CHILD(n, 3)); /* expr */
  	com_addbyte(c, GET_ITER);
***************
*** 1607,1610 ****
--- 1615,1664 ----
  
  static void
+ com_gen_for(struct compiling *c, node *n, node *t, int is_outmost)
+ {
+ 	int break_anchor = 0;
+ 	int anchor = 0;
+ 	int save_begin = c->c_begin;
+ 
+ 	REQ(n, gen_for);
+ 	/* gen_for: for v in test [gen_iter] */
+ 
+ 	com_addfwref(c, SETUP_LOOP, &break_anchor);
+ 	block_push(c, SETUP_LOOP);
+ 
+ 	if (is_outmost) {
+ 		com_addop_varname(c, VAR_LOAD, "[outmost-iterable]");
+ 		com_push(c, 1);
+ 	}
+ 	else {
+ 		com_node(c, CHILD(n, 3));
+ 		com_addbyte(c, GET_ITER); 
+ 	}
+ 
+ 	c->c_begin = c->c_nexti;
+ 	com_set_lineno(c, c->c_last_line);
+ 	com_addfwref(c, FOR_ITER, &anchor);
+ 	com_push(c, 1);
+ 	com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
+ 
+ 	if (NCH(n) == 5) 
+ 		com_gen_iter(c, CHILD(n, 4), t);
+ 	else {
+ 		com_test(c, t);
+ 		com_addbyte(c, YIELD_VALUE);
+ 		com_pop(c, 1);
+ 	}
+ 
+ 	com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
+ 	c->c_begin = save_begin;
+ 
+ 	com_backpatch(c, anchor);
+ 	com_pop(c, 1); /* FOR_ITER has popped this */
+ 	com_addbyte(c, POP_BLOCK);
+ 	block_pop(c, SETUP_LOOP);
+ 	com_backpatch(c, break_anchor);
+ }
+ 
+ static void
  com_list_if(struct compiling *c, node *n, node *e, char *t)
  {
***************
*** 1625,1628 ****
--- 1679,1708 ----
  
  static void
+ com_gen_if(struct compiling *c, node *n, node *t)
+ {
+ 	/* gen_if: 'if' test [gen_iter] */
+ 	int anchor = 0;
+ 	int a=0;
+ 
+ 	com_node(c, CHILD(n, 1));
+ 	com_addfwref(c, JUMP_IF_FALSE, &a);
+ 	com_addbyte(c, POP_TOP);
+ 	com_pop(c, 1);
+ 
+ 	if (NCH(n) == 3)
+ 		com_gen_iter(c, CHILD(n, 2), t);
+ 	else {
+ 		com_test(c, t);
+ 		com_addbyte(c, YIELD_VALUE);
+ 		com_pop(c, 1);
+ 	}
+ 	com_addfwref(c, JUMP_FORWARD, &anchor);
+ 	com_backpatch(c, a);
+ 	/* We jump here with an extra entry which we now pop */
+ 	com_addbyte(c, POP_TOP);
+ 	com_backpatch(c, anchor);
+ }
+ 
+ static void
  com_list_iter(struct compiling *c,
  	      node *p,		/* parent of list_iter node */
***************
*** 1656,1659 ****
--- 1736,1761 ----
  
  static void
+ com_gen_iter(struct compiling *c, node *n, node *t)
+ {
+ 	/* gen_iter: gen_for | gen_if */
+ 	node *ch;
+ 	REQ(n, gen_iter);
+ 
+ 	ch = CHILD(n, 0);
+ 
+ 	switch (TYPE(ch)) {
+ 	case gen_for:
+ 		com_gen_for(c, ch, t, 0);
+ 		break;
+ 	case gen_if:
+ 		com_gen_if(c, ch, t);
+ 		break;
+ 	default:
+ 		com_error(c, PyExc_SystemError,
+ 			  "invalid gen_iter node type");
+ 	}
+ }
+ 
+ static void
  com_list_comprehension(struct compiling *c, node *n)
  {
***************
*** 1690,1693 ****
--- 1792,1841 ----
  
  static void
+ com_generator_expression(struct compiling *c, node *n)
+ {
+ 	/* testlist_gexp: test gen_for */
+ 	/* argument: test gen_for */
+ 	PyCodeObject *co;
+ 
+ 	REQ(CHILD(n, 0), test); 
+ 	REQ(CHILD(n, 1), gen_for); 
+ 
+ 	symtable_enter_scope(c->c_symtable, "<genexpr>", TYPE(n),
+ 		             n->n_lineno);
+ 	co = icompile(n, c);
+ 	symtable_exit_scope(c->c_symtable);
+ 
+ 	if (co == NULL)
+ 		c->c_errors++;
+ 	else {
+ 		int closure = com_make_closure(c, co);
+ 		int i = com_addconst(c, (PyObject *)co);
+ 
+ 		com_addoparg(c, LOAD_CONST, i);
+ 		com_push(c, 1);
+ 		if (closure)
+ 			com_addoparg(c, MAKE_CLOSURE, 0);
+ 		else
+ 			com_addoparg(c, MAKE_FUNCTION, 0);
+ 
+ 		com_test(c, CHILD(CHILD(n, 1), 3));
+ 		com_addbyte(c, GET_ITER);
+ 		com_addoparg(c, CALL_FUNCTION, 1);
+ 		com_pop(c, 1);
+ 
+ 		Py_DECREF(co);
+ 	}
+ }
+ 
+ static void
+ com_testlist_gexp(struct compiling *c, node *n)
+ {
+ 	/* testlist_gexp: test ( gen_for | (',' test)* [','] ) */
+ 	if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for)
+ 		com_generator_expression(c, n);
+ 	else com_list(c, n, 0);
+ }
+ 
+ static void
  com_dictmaker(struct compiling *c, node *n)
  {
***************
*** 1722,1726 ****
  		}
  		else
! 			com_node(c, CHILD(n, 1));
  		break;
  	case LSQB: /* '[' [listmaker] ']' */
--- 1870,1874 ----
  		}
  		else
! 			com_testlist_gexp(c, CHILD(n, 1));
  		break;
  	case LSQB: /* '[' [listmaker] ']' */
***************
*** 1858,1862 ****
  {
  	node *m;
! 	REQ(n, argument); /* [test '='] test; really [keyword '='] test */
  	if (NCH(n) == 1) {
  		if (*pkeywords != NULL) {
--- 2006,2010 ----
  {
  	node *m;
! 	REQ(n, argument); /* [test '='] test [gen_for]; really [keyword '='] test */
  	if (NCH(n) == 1) {
  		if (*pkeywords != NULL) {
***************
*** 1869,1872 ****
--- 2017,2025 ----
  		return;
  	}
+ 	if (NCH(n) == 2) {
+ 		com_generator_expression(c, n);
+ 		return;
+ 	}
+ 
  	m = n;
  	do {
***************
*** 2724,2728 ****
  {
  	int i;
! 	if (TYPE(n) != testlist && TYPE(n) != listmaker)
  		REQ(n, exprlist);
  	if (assigning) {
--- 2877,2882 ----
  {
  	int i;
! 	if (TYPE(n) != testlist && TYPE(n) != testlist_gexp &&
! 	    TYPE(n) != listmaker)
  		REQ(n, exprlist);
  	if (assigning) {
***************
*** 2766,2770 ****
--- 2920,2930 ----
  		case testlist:
  		case testlist1:
+ 		case testlist_gexp:
  			if (NCH(n) > 1) {
+ 				if (TYPE(CHILD(n, 1)) == gen_for) {
+ 					com_error(c, PyExc_SystemError,
+ 				  "assign to generator expression not possible");
+ 					return;
+ 				}
  				if (assigning > OP_APPLY) {
  					com_error(c, PyExc_SyntaxError,
***************
*** 4254,4257 ****
--- 4414,4434 ----
  
  static void
+ compile_generator_expression(struct compiling *c, node *n)
+ {
+ 	/* testlist_gexp: test gen_for */
+ 	/* argument: test gen_for */
+ 	REQ(CHILD(n, 0), test); 
+ 	REQ(CHILD(n, 1), gen_for); 
+ 
+ 	c->c_name = "<generator expression>";
+ 	com_gen_for(c, CHILD(n, 1), CHILD(n, 0), 1);
+ 
+ 	com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
+ 	com_push(c, 1);
+ 	com_addbyte(c, RETURN_VALUE);
+ 	com_pop(c, 1);
+ }
+ 
+ static void
  compile_node(struct compiling *c, node *n)
  {
***************
*** 4301,4304 ****
--- 4478,4486 ----
  		break;
  	
+ 	case testlist_gexp: /* A generator expression */
+ 	case argument:      /* A generator expression */
+ 		compile_generator_expression(c, n);
+ 		break;
+ 
  	default:
  		com_error(c, PyExc_SystemError,
***************
*** 4977,4981 ****
  		}
  	}
- 
  	assert(PyDict_Size(c->c_freevars) == si.si_nfrees);
  
--- 5159,5162 ----
***************
*** 5347,5355 ****
  
  		case yield_stmt:
! 			return 1;
  
  		default:
  			if (look_for_yield(kid))
! 				return 1;
  		}
  	}
--- 5528,5536 ----
  
  		case yield_stmt:
! 			return GENERATOR;
  
  		default:
  			if (look_for_yield(kid))
! 				return GENERATOR;
  		}
  	}
***************
*** 5495,5498 ****
--- 5676,5691 ----
  				symtable_node(st, CHILD(n, i));
  		break;
+ 	case arglist:
+ 		if (NCH(n) > 1)
+ 			for (i = 0; i < NCH(n); ++i) {
+ 				node *ch = CHILD(n, i);
+ 				if (TYPE(ch) == argument && NCH(ch) == 2 &&
+ 				    TYPE(CHILD(ch, 1)) == gen_for) {
+ 					PyErr_SetString(PyExc_SyntaxError,
+ 							"invalid syntax");
+ 					symtable_error(st, n->n_lineno);
+ 					return;
+ 				}
+ 			}
  	/* The remaining cases fall through to default except in
  	   special circumstances.  This requires the individual cases
***************
*** 5505,5508 ****
--- 5698,5706 ----
  			goto loop;
  		}
+ 		else if (TYPE(n) == argument && NCH(n) == 2 &&
+ 			TYPE(CHILD(n, 1)) == gen_for) {
+ 			symtable_generator_expression(st, n);
+ 			break;
+ 		}
  		/* fall through */
  	case listmaker:
***************
*** 5512,5515 ****
--- 5710,5720 ----
  		}
  		/* fall through */
+ 	case testlist_gexp:
+ 		if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) {
+ 			symtable_generator_expression(st, n); 
+ 			break;
+ 		}
+ 		/* fall through */
+ 
  	case atom:
  		if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) {
***************
*** 5716,5719 ****
--- 5921,5944 ----
  
  static void
+ symtable_generator_expression(struct symtable *st, node *n)
+ {
+ 	/* testlist_gexp: test gen_for */
+ 	REQ(CHILD(n, 0), test);
+ 	REQ(CHILD(n, 1), gen_for);
+ 
+ 	symtable_enter_scope(st, "<genexpr>", TYPE(n), n->n_lineno);
+ 	st->st_cur->ste_generator = GENERATOR_EXPRESSION;
+ 
+ 	symtable_add_def(st, "[outmost-iterable]", DEF_PARAM);
+ 	
+ 	symtable_gen_for(st, CHILD(n, 1), 1);
+ 	symtable_node(st, CHILD(n, 0));
+ 	symtable_exit_scope(st);
+ 
+ 	/* for outmost iterable precomputation */
+ 	symtable_node(st, CHILD(CHILD(n, 1), 3)); 
+ }
+ 
+ static void
  symtable_list_for(struct symtable *st, node *n)
  {
***************
*** 5727,5730 ****
--- 5952,5988 ----
  
  static void
+ symtable_gen_for(struct symtable *st, node *n, int is_outmost)
+ {
+ 	REQ(n, gen_for);
+ 
+ 	/* gen_for: for v in test [gen_iter] */
+ 	symtable_assign(st, CHILD(n, 1), 0);
+ 	if (is_outmost)
+ 		symtable_add_use(st, "[outmost-iterable]");
+ 	else
+ 		symtable_node(st, CHILD(n, 3));
+ 
+ 	if (NCH(n) == 5)
+ 		symtable_gen_iter(st, CHILD(n, 4));
+ }
+ 
+ static void
+ symtable_gen_iter(struct symtable *st, node *n)
+ {
+ 	REQ(n, gen_iter);
+ 
+ 	n = CHILD(n, 0);
+ 	if (TYPE(n) == gen_for)
+ 		symtable_gen_for(st, n, 0);
+ 	else {
+ 		REQ(n, gen_if);
+ 		symtable_node(st, CHILD(n, 1));
+ 
+ 		if (NCH(n) == 3)
+ 			symtable_gen_iter(st, CHILD(n, 2));
+ 	}
+ }
+ 
+ static void
  symtable_import(struct symtable *st, node *n)
  {
***************
*** 5814,5817 ****
--- 6072,6086 ----
  		}
  		return;
+ 	case testlist_gexp:
+ 		if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) {
+ 			/* XXX This is an error, but the next pass
+ 			   will catch it. */ 
+ 			return;
+ 		} else {
+ 			for (i = 0; i < NCH(n); i += 2)
+ 				symtable_assign(st, CHILD(n, i), def_flag);
+ 		}
+ 		return;
+ 
  	case exprlist:
  	case testlist:

Index: graminit.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/graminit.c,v
retrieving revision 2.34
retrieving revision 2.35
diff -C2 -d -r2.34 -r2.35
*** graminit.c	4 Aug 2002 17:29:52 -0000	2.34
--- graminit.c	19 May 2004 08:20:16 -0000	2.35
***************
*** 1017,1041 ****
  static arc arcs_49_0[7] = {
  	{16, 1},
! 	{127, 2},
! 	{130, 3},
! 	{133, 4},
  	{12, 5},
! 	{135, 5},
! 	{136, 6},
  };
  static arc arcs_49_1[2] = {
[...1310 lines suppressed...]
  	{1, "lambda"},
! 	{318, 0},
  	{310, 0},
  	{311, 0},
! 	{312, 0},
! 	{315, 0},
  	{1, "class"},
  	{319, 0},
! 	{320, 0},
! 	{322, 0},
  	{323, 0},
+ 	{325, 0},
+ 	{327, 0},
  };
  grammar _PyParser_Grammar = {
! 	72,
  	dfas,
! 	{153, labels},
  	256
  };

Index: symtable.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/symtable.c,v
retrieving revision 2.11
retrieving revision 2.12
diff -C2 -d -r2.11 -r2.12
*** symtable.c	21 May 2003 17:34:50 -0000	2.11
--- symtable.c	19 May 2004 08:20:32 -0000	2.12
***************
*** 67,70 ****
--- 67,72 ----
  	case funcdef:
  	case lambdef:
+ 	case testlist_gexp: /* generator expression */
+ 	case argument:      /* generator expression */
  		ste->ste_type = TYPE_FUNCTION;
  		break;




More information about the Python-checkins mailing list