From 85f363990cbd6df21015eebdc171c533176e3407 Mon Sep 17 00:00:00 2001 From: Fred Drake Date: Tue, 11 Jul 2000 17:53:00 +0000 Subject: 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. --- Include/errcode.h | 6 ++++-- Include/parsetok.h | 2 ++ Lib/test/output/test_exceptions | 4 ++++ Lib/test/test_exceptions.py | 8 ++++++++ Parser/parser.c | 12 +++++++++++- Parser/parser.h | 3 ++- Parser/parsetok.c | 4 ++-- Parser/tokenizer.c | 14 +++++--------- Python/exceptions.c | 17 +++++++++++++++++ Python/pythonrun.c | 29 +++++++++++++++++++++++++---- 10 files changed, 80 insertions(+), 19 deletions(-) diff --git a/Include/errcode.h b/Include/errcode.h index b872e18..0683317 100644 --- a/Include/errcode.h +++ b/Include/errcode.h @@ -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_DONE 16 /* Parsing complete */ #define E_ERROR 17 /* Execution error */ -#define E_INDENT 18 /* Invalid indentation detected */ -#define E_OVERFLOW 19 /* Node had too many children */ +#define E_TABSPACE 18 /* Invalid indentation detected */ +#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 } diff --git a/Include/parsetok.h b/Include/parsetok.h index 5244e3f..71e7d89 100644 --- a/Include/parsetok.h +++ b/Include/parsetok.h @@ -22,6 +22,8 @@ typedef struct { int lineno; int offset; char *text; + int token; + int expected; } perrdetail; extern DL_IMPORT(node *) PyParser_ParseString(char *, grammar *, int, diff --git a/Lib/test/output/test_exceptions b/Lib/test/output/test_exceptions index 5605114..9e021d2 100644 --- a/Lib/test/output/test_exceptions +++ b/Lib/test/output/test_exceptions @@ -28,6 +28,10 @@ RuntimeError spam SyntaxError spam +IndentationError +spam +TabError +spam SystemError (hard to reproduce) spam diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 7bc515c..06861df 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -86,6 +86,14 @@ r(SyntaxError) try: exec '/\n' 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", '', 'exec') +#except TabError: pass +#else: raise TestFailed + r(SystemError) print '(hard to reproduce)' diff --git a/Parser/parser.c b/Parser/parser.c index ee40f21..b74de7f 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -205,11 +205,12 @@ classify(g, type, str) } int -PyParser_AddToken(ps, type, str, lineno) +PyParser_AddToken(ps, type, str, lineno, expected_ret) register parser_state *ps; register int type; char *str; int lineno; + int *expected_ret; { register int ilabel; int err; @@ -285,6 +286,15 @@ PyParser_AddToken(ps, type, str, lineno) /* Stuck, report syntax error */ 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; } } diff --git a/Parser/parser.h b/Parser/parser.h index 6087373..d0df8cf 100644 --- a/Parser/parser.h +++ b/Parser/parser.h @@ -38,7 +38,8 @@ typedef struct { parser_state *PyParser_New(grammar *g, int start); 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); #ifdef __cplusplus diff --git a/Parser/parsetok.c b/Parser/parsetok.c index 9ac1606..9d090f1 100644 --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -139,8 +139,8 @@ parsetok(tok, g, start, err_ret) strncpy(str, a, len); str[len] = '\0'; if ((err_ret->error = - PyParser_AddToken(ps, (int)type, str, - tok->lineno)) != E_OK) { + PyParser_AddToken(ps, (int)type, str, tok->lineno, + &(err_ret->expected))) != E_OK) { if (err_ret->error != E_DONE) PyMem_DEL(str); break; diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 0ef3fc0..d4ec345 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -412,13 +412,13 @@ indenterror(tok) struct tok_state *tok; { if (tok->alterror) { - tok->done = E_INDENT; + tok->done = E_TABSPACE; tok->cur = tok->inp; return 1; } if (tok->altwarning) { - PySys_WriteStderr("%s: inconsistent tab/space usage\n", - tok->filename); + PySys_WriteStderr("%s: inconsistent use of tabs and spaces " + "in indentation\n", tok->filename); tok->altwarning = 0; } return 0; @@ -484,9 +484,7 @@ PyTokenizer_Get(tok, p_start, p_end) else if (col > tok->indstack[tok->indent]) { /* Indent -- always one */ if (tok->indent+1 >= MAXINDENT) { - PySys_WriteStderr( - "excessive indent\n"); - tok->done = E_TOKEN; + tok->done = E_TOODEEP; tok->cur = tok->inp; return ERRORTOKEN; } @@ -506,9 +504,7 @@ PyTokenizer_Get(tok, p_start, p_end) tok->indent--; } if (col != tok->indstack[tok->indent]) { - PySys_WriteStderr( - "inconsistent dedent\n"); - tok->done = E_TOKEN; + tok->done = E_DEDENT; tok->cur = tok->inp; return ERRORTOKEN; } diff --git a/Python/exceptions.c b/Python/exceptions.c index f766ba5..a70e6c6 100644 --- a/Python/exceptions.c +++ b/Python/exceptions.c @@ -68,6 +68,11 @@ Exception\n\ |\n\ +-- AttributeError\n\ +-- SyntaxError\n\ + | |\n\ + | +-- IndentationError\n\ + | |\n\ + | +-- TabError\n\ + |\n\ +-- TypeError\n\ +-- AssertionError\n\ +-- LookupError\n\ @@ -783,6 +788,12 @@ the Python version, and the hardware/OS platform and version."; static char MemoryError__doc__[] = "Out of memory."; +static char +IndentationError__doc__[] = "Improper indentation."; + +static char +TabError__doc__[] = "Improper mixture of spaces and tabs."; + /* module global functions */ @@ -817,6 +828,8 @@ PyObject *PyExc_OverflowError; PyObject *PyExc_RuntimeError; PyObject *PyExc_NotImplementedError; PyObject *PyExc_SyntaxError; +PyObject *PyExc_IndentationError; +PyObject *PyExc_TabError; PyObject *PyExc_SystemError; PyObject *PyExc_SystemExit; PyObject *PyExc_UnboundLocalError; @@ -878,6 +891,10 @@ exctable[] = { {"AttributeError", &PyExc_AttributeError, 0, AttributeError__doc__}, {"SyntaxError", &PyExc_SyntaxError, 0, SyntaxError__doc__, SyntaxError_methods, SyntaxError__classinit__}, + {"IndentationError", &PyExc_IndentationError, &PyExc_SyntaxError, + IndentationError__doc__}, + {"TabError", &PyExc_TabError, &PyExc_IndentationError, + TabError__doc__}, {"AssertionError", &PyExc_AssertionError, 0, AssertionError__doc__}, {"LookupError", &PyExc_LookupError, 0, LookupError__doc__}, {"IndexError", &PyExc_IndexError, &PyExc_LookupError, diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 74dffae..9cc8072 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -14,6 +14,7 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. #include "grammar.h" #include "node.h" +#include "token.h" #include "parsetok.h" #include "errcode.h" #include "compile.h" @@ -983,8 +984,9 @@ static void err_input(err) perrdetail *err; { - PyObject *v, *w; + PyObject *v, *w, *errtype; char *msg = NULL; + errtype = PyExc_SyntaxError; v = Py_BuildValue("(ziiz)", err->filename, err->lineno, err->offset, err->text); if (err->text != NULL) { @@ -993,7 +995,17 @@ err_input(err) } switch (err->error) { 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; case E_TOKEN: msg = "invalid token"; @@ -1009,12 +1021,21 @@ err_input(err) case E_EOF: msg = "unexpected EOF while parsing"; break; - case E_INDENT: + case E_TABSPACE: + errtype = PyExc_TabError; msg = "inconsistent use of tabs and spaces in indentation"; break; case E_OVERFLOW: msg = "expression too long"; 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: fprintf(stderr, "error=%d\n", err->error); msg = "unknown parsing error"; @@ -1022,7 +1043,7 @@ err_input(err) } w = Py_BuildValue("(sO)", msg, v); Py_XDECREF(v); - PyErr_SetObject(PyExc_SyntaxError, w); + PyErr_SetObject(errtype, w); Py_XDECREF(w); } -- cgit v0.12