Create two new exceptions: IndentationError and TabError. These are

used for indentation related errors.  This patch includes Ping's
improvements for indentation-related error messages.

Closes SourceForge patches #100734 and #100856.
This commit is contained in:
Fred Drake 2000-07-11 17:53:00 +00:00
parent 88e1932930
commit 85f363990c
10 changed files with 80 additions and 19 deletions

View File

@ -30,8 +30,10 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#define E_NOMEM 15 /* Ran out of memory */ #define E_NOMEM 15 /* Ran out of memory */
#define E_DONE 16 /* Parsing complete */ #define E_DONE 16 /* Parsing complete */
#define E_ERROR 17 /* Execution error */ #define E_ERROR 17 /* Execution error */
#define E_INDENT 18 /* Invalid indentation detected */ #define E_TABSPACE 18 /* Invalid indentation detected */
#define E_OVERFLOW 19 /* Node had too many children */ #define E_OVERFLOW 19 /* Node had too many children */
#define E_TOODEEP 20 /* Too many indentation levels */
#define E_DEDENT 21 /* No matching outer block for dedent */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -22,6 +22,8 @@ typedef struct {
int lineno; int lineno;
int offset; int offset;
char *text; char *text;
int token;
int expected;
} perrdetail; } perrdetail;
extern DL_IMPORT(node *) PyParser_ParseString(char *, grammar *, int, extern DL_IMPORT(node *) PyParser_ParseString(char *, grammar *, int,

View File

@ -28,6 +28,10 @@ RuntimeError
spam spam
SyntaxError SyntaxError
spam spam
IndentationError
spam
TabError
spam
SystemError SystemError
(hard to reproduce) (hard to reproduce)
spam spam

View File

@ -86,6 +86,14 @@ r(SyntaxError)
try: exec '/\n' try: exec '/\n'
except SyntaxError: pass except SyntaxError: pass
r(IndentationError)
r(TabError)
# can only be tested under -tt, and is the only test for -tt
#try: compile("try:\n\t1/0\n \t1/0\nfinally:\n pass\n", '<string>', 'exec')
#except TabError: pass
#else: raise TestFailed
r(SystemError) r(SystemError)
print '(hard to reproduce)' print '(hard to reproduce)'

View File

@ -205,11 +205,12 @@ classify(g, type, str)
} }
int int
PyParser_AddToken(ps, type, str, lineno) PyParser_AddToken(ps, type, str, lineno, expected_ret)
register parser_state *ps; register parser_state *ps;
register int type; register int type;
char *str; char *str;
int lineno; int lineno;
int *expected_ret;
{ {
register int ilabel; register int ilabel;
int err; int err;
@ -285,6 +286,15 @@ PyParser_AddToken(ps, type, str, lineno)
/* Stuck, report syntax error */ /* Stuck, report syntax error */
D(printf(" Error.\n")); D(printf(" Error.\n"));
if (expected_ret) {
if (s->s_lower == s->s_upper - 1) {
/* Only one possible expected token */
*expected_ret = ps->p_grammar->
g_ll.ll_label[s->s_lower].lb_type;
}
else
*expected_ret = -1;
}
return E_SYNTAX; return E_SYNTAX;
} }
} }

View File

@ -38,7 +38,8 @@ typedef struct {
parser_state *PyParser_New(grammar *g, int start); parser_state *PyParser_New(grammar *g, int start);
void PyParser_Delete(parser_state *ps); void PyParser_Delete(parser_state *ps);
int PyParser_AddToken(parser_state *ps, int type, char *str, int lineno); int PyParser_AddToken(parser_state *ps, int type, char *str, int lineno,
int *expected_ret);
void PyGrammar_AddAccelerators(grammar *g); void PyGrammar_AddAccelerators(grammar *g);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -139,8 +139,8 @@ parsetok(tok, g, start, err_ret)
strncpy(str, a, len); strncpy(str, a, len);
str[len] = '\0'; str[len] = '\0';
if ((err_ret->error = if ((err_ret->error =
PyParser_AddToken(ps, (int)type, str, PyParser_AddToken(ps, (int)type, str, tok->lineno,
tok->lineno)) != E_OK) { &(err_ret->expected))) != E_OK) {
if (err_ret->error != E_DONE) if (err_ret->error != E_DONE)
PyMem_DEL(str); PyMem_DEL(str);
break; break;

View File

@ -412,13 +412,13 @@ indenterror(tok)
struct tok_state *tok; struct tok_state *tok;
{ {
if (tok->alterror) { if (tok->alterror) {
tok->done = E_INDENT; tok->done = E_TABSPACE;
tok->cur = tok->inp; tok->cur = tok->inp;
return 1; return 1;
} }
if (tok->altwarning) { if (tok->altwarning) {
PySys_WriteStderr("%s: inconsistent tab/space usage\n", PySys_WriteStderr("%s: inconsistent use of tabs and spaces "
tok->filename); "in indentation\n", tok->filename);
tok->altwarning = 0; tok->altwarning = 0;
} }
return 0; return 0;
@ -484,9 +484,7 @@ PyTokenizer_Get(tok, p_start, p_end)
else if (col > tok->indstack[tok->indent]) { else if (col > tok->indstack[tok->indent]) {
/* Indent -- always one */ /* Indent -- always one */
if (tok->indent+1 >= MAXINDENT) { if (tok->indent+1 >= MAXINDENT) {
PySys_WriteStderr( tok->done = E_TOODEEP;
"excessive indent\n");
tok->done = E_TOKEN;
tok->cur = tok->inp; tok->cur = tok->inp;
return ERRORTOKEN; return ERRORTOKEN;
} }
@ -506,9 +504,7 @@ PyTokenizer_Get(tok, p_start, p_end)
tok->indent--; tok->indent--;
} }
if (col != tok->indstack[tok->indent]) { if (col != tok->indstack[tok->indent]) {
PySys_WriteStderr( tok->done = E_DEDENT;
"inconsistent dedent\n");
tok->done = E_TOKEN;
tok->cur = tok->inp; tok->cur = tok->inp;
return ERRORTOKEN; return ERRORTOKEN;
} }

View File

@ -68,6 +68,11 @@ Exception\n\
|\n\ |\n\
+-- AttributeError\n\ +-- AttributeError\n\
+-- SyntaxError\n\ +-- SyntaxError\n\
| |\n\
| +-- IndentationError\n\
| |\n\
| +-- TabError\n\
|\n\
+-- TypeError\n\ +-- TypeError\n\
+-- AssertionError\n\ +-- AssertionError\n\
+-- LookupError\n\ +-- LookupError\n\
@ -783,6 +788,12 @@ the Python version, and the hardware/OS platform and version.";
static char static char
MemoryError__doc__[] = "Out of memory."; MemoryError__doc__[] = "Out of memory.";
static char
IndentationError__doc__[] = "Improper indentation.";
static char
TabError__doc__[] = "Improper mixture of spaces and tabs.";
/* module global functions */ /* module global functions */
@ -817,6 +828,8 @@ PyObject *PyExc_OverflowError;
PyObject *PyExc_RuntimeError; PyObject *PyExc_RuntimeError;
PyObject *PyExc_NotImplementedError; PyObject *PyExc_NotImplementedError;
PyObject *PyExc_SyntaxError; PyObject *PyExc_SyntaxError;
PyObject *PyExc_IndentationError;
PyObject *PyExc_TabError;
PyObject *PyExc_SystemError; PyObject *PyExc_SystemError;
PyObject *PyExc_SystemExit; PyObject *PyExc_SystemExit;
PyObject *PyExc_UnboundLocalError; PyObject *PyExc_UnboundLocalError;
@ -878,6 +891,10 @@ exctable[] = {
{"AttributeError", &PyExc_AttributeError, 0, AttributeError__doc__}, {"AttributeError", &PyExc_AttributeError, 0, AttributeError__doc__},
{"SyntaxError", &PyExc_SyntaxError, 0, SyntaxError__doc__, {"SyntaxError", &PyExc_SyntaxError, 0, SyntaxError__doc__,
SyntaxError_methods, SyntaxError__classinit__}, SyntaxError_methods, SyntaxError__classinit__},
{"IndentationError", &PyExc_IndentationError, &PyExc_SyntaxError,
IndentationError__doc__},
{"TabError", &PyExc_TabError, &PyExc_IndentationError,
TabError__doc__},
{"AssertionError", &PyExc_AssertionError, 0, AssertionError__doc__}, {"AssertionError", &PyExc_AssertionError, 0, AssertionError__doc__},
{"LookupError", &PyExc_LookupError, 0, LookupError__doc__}, {"LookupError", &PyExc_LookupError, 0, LookupError__doc__},
{"IndexError", &PyExc_IndexError, &PyExc_LookupError, {"IndexError", &PyExc_IndexError, &PyExc_LookupError,

View File

@ -14,6 +14,7 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#include "grammar.h" #include "grammar.h"
#include "node.h" #include "node.h"
#include "token.h"
#include "parsetok.h" #include "parsetok.h"
#include "errcode.h" #include "errcode.h"
#include "compile.h" #include "compile.h"
@ -983,8 +984,9 @@ static void
err_input(err) err_input(err)
perrdetail *err; perrdetail *err;
{ {
PyObject *v, *w; PyObject *v, *w, *errtype;
char *msg = NULL; char *msg = NULL;
errtype = PyExc_SyntaxError;
v = Py_BuildValue("(ziiz)", err->filename, v = Py_BuildValue("(ziiz)", err->filename,
err->lineno, err->offset, err->text); err->lineno, err->offset, err->text);
if (err->text != NULL) { if (err->text != NULL) {
@ -993,7 +995,17 @@ err_input(err)
} }
switch (err->error) { switch (err->error) {
case E_SYNTAX: case E_SYNTAX:
msg = "invalid syntax"; errtype = PyExc_IndentationError;
if (err->expected == INDENT)
msg = "expected an indented block";
else if (err->token == INDENT)
msg = "unexpected indent";
else if (err->token == DEDENT)
msg = "unexpected unindent";
else {
errtype = PyExc_SyntaxError;
msg = "invalid syntax";
}
break; break;
case E_TOKEN: case E_TOKEN:
msg = "invalid token"; msg = "invalid token";
@ -1009,12 +1021,21 @@ err_input(err)
case E_EOF: case E_EOF:
msg = "unexpected EOF while parsing"; msg = "unexpected EOF while parsing";
break; break;
case E_INDENT: case E_TABSPACE:
errtype = PyExc_TabError;
msg = "inconsistent use of tabs and spaces in indentation"; msg = "inconsistent use of tabs and spaces in indentation";
break; break;
case E_OVERFLOW: case E_OVERFLOW:
msg = "expression too long"; msg = "expression too long";
break; break;
case E_DEDENT:
errtype = PyExc_IndentationError;
msg = "unindent does not match any outer indentation level";
break;
case E_TOODEEP:
errtype = PyExc_IndentationError;
msg = "too many levels of indentation";
break;
default: default:
fprintf(stderr, "error=%d\n", err->error); fprintf(stderr, "error=%d\n", err->error);
msg = "unknown parsing error"; msg = "unknown parsing error";
@ -1022,7 +1043,7 @@ err_input(err)
} }
w = Py_BuildValue("(sO)", msg, v); w = Py_BuildValue("(sO)", msg, v);
Py_XDECREF(v); Py_XDECREF(v);
PyErr_SetObject(PyExc_SyntaxError, w); PyErr_SetObject(errtype, w);
Py_XDECREF(w); Py_XDECREF(w);
} }