[Python-checkins] CVS: python/dist/src/Python compile.c,2.205,2.206

Tim Peters tim_one@users.sourceforge.net
Wed, 27 Jun 2001 18:52:25 -0700


Update of /cvsroot/python/python/dist/src/Python
In directory usw-pr-cvs1:/tmp/cvs-serv21972/python/dist/src/Python

Modified Files:
	compile.c 
Log Message:
Another "if 0:" hack, this time to complain about otherwise invisible
"return expr" instances in generators (which latter may be generators
due to otherwise invisible "yield" stmts hiding in "if 0" blocks).
This was fun the first time, but this has gotten truly ugly now.


Index: compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.205
retrieving revision 2.206
diff -C2 -r2.205 -r2.206
*** compile.c	2001/06/26 03:36:28	2.205
--- compile.c	2001/06/28 01:52:22	2.206
***************
*** 2877,2880 ****
--- 2877,2919 ----
  }
  
+ 
+ /* Look under n for a return stmt with an expression.
+  * This hack is used to find illegal returns under "if 0:" blocks in
+  * functions already known to be generators (as determined by the symtable
+  * pass).
+  * Return the offending return node if found, else NULL.
+  */
+ static node *
+ look_for_offending_return(node *n)
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < NCH(n); ++i) {
+ 		node *kid = CHILD(n, i);
+ 
+ 		switch (TYPE(kid)) {
+ 			case classdef:
+ 			case funcdef:
+ 			case lambdef:
+ 				/* Stuff in nested functions & classes doesn't
+ 				   affect the code block we started in. */
+ 				return NULL;
+ 
+ 			case return_stmt:
+ 				if (NCH(kid) > 1)
+ 					return kid;
+ 				break;
+ 
+ 			default: {
+ 				node *bad = look_for_offending_return(kid);
+ 				if (bad != NULL)
+ 					return bad;
+ 			}
+ 		}
+ 	}
+ 
+ 	return NULL;
+ }			
+ 
  static void
  com_if_stmt(struct compiling *c, node *n)
***************
*** 2887,2892 ****
  		int a = 0;
  		node *ch = CHILD(n, i+1);
! 		if (is_constant_false(c, ch))
  			continue;
  		if (i > 0)
  			com_addoparg(c, SET_LINENO, ch->n_lineno);
--- 2926,2947 ----
  		int a = 0;
  		node *ch = CHILD(n, i+1);
! 		if (is_constant_false(c, ch)) {
! 			/* We're going to skip this block.  However, if this
! 			   is a generator, we have to check the dead code
! 			   anyway to make sure there aren't any return stmts
! 			   with expressions, in the same scope. */
! 			if (c->c_flags & CO_GENERATOR) {
! 				node *p = look_for_offending_return(n);
! 				if (p != NULL) {
! 					int savelineno = c->c_lineno;
! 					c->c_lineno = p->n_lineno;
! 					com_error(c, PyExc_SyntaxError,
! 			  	   		"'return' with argument "
! 			  	   		"inside generator");
! 			  	   	c->c_lineno = savelineno;
! 				}
! 			}
  			continue;
+ 		}
  		if (i > 0)
  			com_addoparg(c, SET_LINENO, ch->n_lineno);
***************
*** 4841,4845 ****
  #define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE)
  
! /* Look for a yield stmt under n.  Return 1 if found, else 0. */
  static int
  look_for_yield(node *n)
--- 4896,4903 ----
  #define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE)
  
! /* Look for a yield stmt under n.  Return 1 if found, else 0.
!    This hack is used to look inside "if 0:" blocks (which are normally
!    ignored) in case those are the only places a yield occurs (so that this
!    function is a generator). */
  static int
  look_for_yield(node *n)
***************
*** 4854,4857 ****
--- 4912,4916 ----
  		case classdef:
  		case funcdef:
+ 		case lambdef:
  			/* Stuff in nested functions and classes can't make
  			   the parent a generator. */