[Python-checkins] CVS: python/dist/src/Python future.c,2.3,2.4 compile.c,2.176,2.177 errors.c,2.59,2.60

Jeremy Hylton jhylton@users.sourceforge.net
Wed, 28 Feb 2001 09:47:14 -0800


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

Modified Files:
	future.c compile.c errors.c 
Log Message:
Improve SyntaxErrors for bad future statements.  Set file and location
for errors raised in future.c.

Move some helper functions from compile.c to errors.c and make them
API functions: PyErr_SyntaxLocation() and PyErr_ProgramText().



Index: future.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/future.c,v
retrieving revision 2.3
retrieving revision 2.4
diff -C2 -r2.3 -r2.4
*** future.c	2001/02/28 02:26:14	2.3
--- future.c	2001/02/28 17:47:12	2.4
***************
*** 7,28 ****
  
  #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
  
  #define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
  
  static int
! future_check_features(PyFutureFeatures *ff, node *n)
  {
  	int i;
  	char *feature;
  
  	REQ(n, import_stmt); /* must by from __future__ import ... */
  
  	for (i = 3; i < NCH(n); ++i) {
! 		feature = STR(CHILD(CHILD(n, i), 0));
  		if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
  			ff->ff_nested_scopes = 1;
  		} else {
  			PyErr_Format(PyExc_SyntaxError,
  				     UNDEFINED_FUTURE_FEATURE, feature);
  			return -1;
  		}
--- 7,44 ----
  
  #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
+ #define FUTURE_IMPORT_STAR "future statement does not support import *"
  
  #define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
  
  static int
! future_check_features(PyFutureFeatures *ff, node *n, char *filename)
  {
  	int i;
  	char *feature;
+ 	node *ch;
  
  	REQ(n, import_stmt); /* must by from __future__ import ... */
  
  	for (i = 3; i < NCH(n); ++i) {
! 		ch = CHILD(n, i);
! 		if (TYPE(ch) == STAR) {
! 			PyErr_SetString(PyExc_SyntaxError,
! 					FUTURE_IMPORT_STAR);
! 			PyErr_SyntaxLocation(filename, ch->n_lineno);
! 			return -1;
! 		}
! 		REQ(ch, import_as_name);
! 		feature = STR(CHILD(ch, 0));
  		if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
  			ff->ff_nested_scopes = 1;
+ 		} else if (strcmp(feature, "braces") == 0) {
+ 			PyErr_SetString(PyExc_SyntaxError,
+ 					"not a chance");
+ 			PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
+ 			return -1;
  		} else {
  			PyErr_Format(PyExc_SyntaxError,
  				     UNDEFINED_FUTURE_FEATURE, feature);
+ 			PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
  			return -1;
  		}
***************
*** 37,40 ****
--- 53,57 ----
  			"from __future__ imports must occur at the "
  			"beginning of the file");
+ 	PyErr_SyntaxLocation(filename, n->n_lineno);
  	/* XXX set filename and lineno */
  }
***************
*** 46,51 ****
  stmt: simple_stmt | compound_stmt
  simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
! small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
! import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
  import_as_name: NAME [NAME NAME]
  dotted_as_name: dotted_name [NAME NAME]
--- 63,70 ----
  stmt: simple_stmt | compound_stmt
  simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
! small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt 
!     | import_stmt | global_stmt | exec_stmt | assert_stmt
! import_stmt: 'import' dotted_as_name (',' dotted_as_name)* 
!     | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
  import_as_name: NAME [NAME NAME]
  dotted_as_name: dotted_name [NAME NAME]
***************
*** 65,73 ****
   loop:
  
- /*	fprintf(stderr, "future_parse(%d, %d, %s, %d)\n",
- 		TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n),
- 		n->n_lineno);
- */
- 
  	switch (TYPE(n)) {
  
--- 84,87 ----
***************
*** 163,167 ****
  		if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
  			return 0;
! 		if (future_check_features(ff, n) < 0)
  			return -1;
  		ff->ff_last_lineno = n->n_lineno + 1;
--- 177,181 ----
  		if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
  			return 0;
! 		if (future_check_features(ff, n, filename) < 0)
  			return -1;
  		ff->ff_last_lineno = n->n_lineno + 1;

Index: compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.176
retrieving revision 2.177
diff -C2 -r2.176 -r2.177
*** compile.c	2001/02/28 07:07:43	2.176
--- compile.c	2001/02/28 17:47:12	2.177
***************
*** 382,428 ****
  }
  
- /* com_fetch_program_text will attempt to load the line of text that
-    the exception refers to.  If it fails, it will return NULL but will
-    not set an exception. 
- 
-    XXX The functionality of this function is quite similar to the
-    functionality in tb_displayline() in traceback.c.
- */
- 
- static PyObject *
- fetch_program_text(char *filename, int lineno)
- {
- 	FILE *fp;
- 	int i;
- 	char linebuf[1000];
- 
- 	if (filename == NULL || lineno <= 0)
- 		return NULL;
- 	fp = fopen(filename, "r");
- 	if (fp == NULL)
- 		return NULL;
- 	for (i = 0; i < lineno; i++) {
- 		char *pLastChar = &linebuf[sizeof(linebuf) - 2];
- 		do {
- 			*pLastChar = '\0';
- 			if (fgets(linebuf, sizeof linebuf, fp) == NULL)
- 				break;
- 			/* fgets read *something*; if it didn't get as
- 			   far as pLastChar, it must have found a newline
- 			   or hit the end of the file;	if pLastChar is \n,
- 			   it obviously found a newline; else we haven't
- 			   yet seen a newline, so must continue */
- 		} while (*pLastChar != '\0' && *pLastChar != '\n');
- 	}
- 	fclose(fp);
- 	if (i == lineno) {
- 		char *p = linebuf;
- 		while (*p == ' ' || *p == '\t' || *p == '\014')
- 			p++;
- 		return PyString_FromString(p);
- 	}
- 	return NULL;
- }
- 
  static void
  com_error(struct compiling *c, PyObject *exc, char *msg)
--- 382,385 ----
***************
*** 446,450 ****
  		return; /* MemoryError, too bad */
  
! 	line = fetch_program_text(c->c_filename, c->c_lineno);
  	if (line == NULL) {
  		Py_INCREF(Py_None);
--- 403,407 ----
  		return; /* MemoryError, too bad */
  
! 	line = PyErr_ProgramText(c->c_filename, c->c_lineno);
  	if (line == NULL) {
  		Py_INCREF(Py_None);
***************
*** 4029,4067 ****
  /* Helper function for setting lineno and filename */
  
- static void
- set_error_location(char *filename, int lineno)
- {
- 	PyObject *exc, *v, *tb, *tmp;
- 
- 	/* add attributes for the line number and filename for the error */
- 	PyErr_Fetch(&exc, &v, &tb);
- 	PyErr_NormalizeException(&exc, &v, &tb);
- 	tmp = PyInt_FromLong(lineno);
- 	if (tmp == NULL)
- 		PyErr_Clear();
- 	else {
- 		if (PyObject_SetAttrString(v, "lineno", tmp))
- 			PyErr_Clear();
- 		Py_DECREF(tmp);
- 	}
- 	if (filename != NULL) {
- 		tmp = PyString_FromString(filename);
- 		if (tmp == NULL)
- 			PyErr_Clear();
- 		else {
- 			if (PyObject_SetAttrString(v, "filename", tmp))
- 				PyErr_Clear();
- 			Py_DECREF(tmp);
- 		}
- 
- 		tmp = fetch_program_text(filename, lineno);
- 		if (tmp) {
- 			PyObject_SetAttrString(v, "text", tmp);
- 			Py_DECREF(tmp);
- 		}
- 	}
- 	PyErr_Restore(exc, v, tb);
- }
- 
  static int
  symtable_build(struct compiling *c, node *n)
--- 3986,3989 ----
***************
*** 4199,4203 ****
  					     ILLEGAL_DYNAMIC_SCOPE, 
  				     PyString_AS_STRING(ste->ste_name));
! 				set_error_location(c->c_symtable->st_filename,
  						   ste->ste_lineno);
  				return -1;
--- 4121,4125 ----
  					     ILLEGAL_DYNAMIC_SCOPE, 
  				     PyString_AS_STRING(ste->ste_name));
! 				PyErr_SyntaxLocation(c->c_symtable->st_filename,
  						   ste->ste_lineno);
  				return -1;
***************
*** 4274,4278 ****
  				PyErr_Format(PyExc_SyntaxError, LOCAL_GLOBAL,
  					     PyString_AS_STRING(name));
! 				set_error_location(st->st_filename, 
  						   ste->ste_lineno);
  				st->st_errors++;
--- 4196,4200 ----
  				PyErr_Format(PyExc_SyntaxError, LOCAL_GLOBAL,
  					     PyString_AS_STRING(name));
! 				PyErr_SyntaxLocation(st->st_filename, 
  						   ste->ste_lineno);
  				st->st_errors++;
***************
*** 4582,4586 ****
  		    PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
  				 PyString_AsString(name));
! 		    set_error_location(st->st_filename,
  				       st->st_cur->ste_lineno);
  		    return -1;
--- 4504,4508 ----
  		    PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
  				 PyString_AsString(name));
! 		    PyErr_SyntaxLocation(st->st_filename,
  				       st->st_cur->ste_lineno);
  		    return -1;
***************
*** 4905,4909 ****
  				     "name '%.400s' is local and global",
  					     name);
! 				set_error_location(st->st_filename,
  						   st->st_cur->ste_lineno);
  				st->st_errors++;
--- 4827,4831 ----
  				     "name '%.400s' is local and global",
  					     name);
! 				PyErr_SyntaxLocation(st->st_filename,
  						   st->st_cur->ste_lineno);
  				st->st_errors++;
***************
*** 4959,4963 ****
  				PyErr_SetString(PyExc_SyntaxError,
  						LATE_FUTURE);
!  				set_error_location(st->st_filename,
  						   n->n_lineno);
  				st->st_errors++;
--- 4881,4885 ----
  				PyErr_SetString(PyExc_SyntaxError,
  						LATE_FUTURE);
!  				PyErr_SyntaxLocation(st->st_filename,
  						   n->n_lineno);
  				st->st_errors++;

Index: errors.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/errors.c,v
retrieving revision 2.59
retrieving revision 2.60
diff -C2 -r2.59 -r2.60
*** errors.c	2000/12/15 21:58:52	2.59
--- errors.c	2001/02/28 17:47:12	2.60
***************
*** 623,624 ****
--- 623,703 ----
  	}
  }
+ 
+ void
+ PyErr_SyntaxLocation(char *filename, int lineno)
+ {
+ 	PyObject *exc, *v, *tb, *tmp;
+ 
+ 	/* add attributes for the line number and filename for the error */
+ 	PyErr_Fetch(&exc, &v, &tb);
+ 	PyErr_NormalizeException(&exc, &v, &tb);
+ 	/* XXX check that it is, indeed, a syntax error */
+ 	tmp = PyInt_FromLong(lineno);
+ 	if (tmp == NULL)
+ 		PyErr_Clear();
+ 	else {
+ 		if (PyObject_SetAttrString(v, "lineno", tmp))
+ 			PyErr_Clear();
+ 		Py_DECREF(tmp);
+ 	}
+ 	if (filename != NULL) {
+ 		tmp = PyString_FromString(filename);
+ 		if (tmp == NULL)
+ 			PyErr_Clear();
+ 		else {
+ 			if (PyObject_SetAttrString(v, "filename", tmp))
+ 				PyErr_Clear();
+ 			Py_DECREF(tmp);
+ 		}
+ 
+ 		tmp = PyErr_ProgramText(filename, lineno);
+ 		if (tmp) {
+ 			PyObject_SetAttrString(v, "text", tmp);
+ 			Py_DECREF(tmp);
+ 		}
+ 	}
+ 	PyErr_Restore(exc, v, tb);
+ }
+ 
+ /* com_fetch_program_text will attempt to load the line of text that
+    the exception refers to.  If it fails, it will return NULL but will
+    not set an exception. 
+ 
+    XXX The functionality of this function is quite similar to the
+    functionality in tb_displayline() in traceback.c.
+ */
+ 
+ PyObject *
+ PyErr_ProgramText(char *filename, int lineno)
+ {
+ 	FILE *fp;
+ 	int i;
+ 	char linebuf[1000];
+ 
+ 	if (filename == NULL || lineno <= 0)
+ 		return NULL;
+ 	fp = fopen(filename, "r");
+ 	if (fp == NULL)
+ 		return NULL;
+ 	for (i = 0; i < lineno; i++) {
+ 		char *pLastChar = &linebuf[sizeof(linebuf) - 2];
+ 		do {
+ 			*pLastChar = '\0';
+ 			if (fgets(linebuf, sizeof linebuf, fp) == NULL)
+ 				break;
+ 			/* fgets read *something*; if it didn't get as
+ 			   far as pLastChar, it must have found a newline
+ 			   or hit the end of the file;	if pLastChar is \n,
+ 			   it obviously found a newline; else we haven't
+ 			   yet seen a newline, so must continue */
+ 		} while (*pLastChar != '\0' && *pLastChar != '\n');
+ 	}
+ 	fclose(fp);
+ 	if (i == lineno) {
+ 		char *p = linebuf;
+ 		while (*p == ' ' || *p == '\t' || *p == '\014')
+ 			p++;
+ 		return PyString_FromString(p);
+ 	}
+ 	return NULL;
+ }