]> granicus.if.org Git - python/commitdiff
Create two new exceptions: IndentationError and TabError. These are
authorFred Drake <fdrake@acm.org>
Tue, 11 Jul 2000 17:53:00 +0000 (17:53 +0000)
committerFred Drake <fdrake@acm.org>
Tue, 11 Jul 2000 17:53:00 +0000 (17:53 +0000)
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
Include/parsetok.h
Lib/test/output/test_exceptions
Lib/test/test_exceptions.py
Parser/parser.c
Parser/parser.h
Parser/parsetok.c
Parser/tokenizer.c
Python/exceptions.c
Python/pythonrun.c

index b872e182062a1dfc9fafe2c3f2435bc530a56b38..068331708bfbd0486da7461f0277924465794a10 100644 (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_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
 }
index 5244e3f837eb14f04a8a607e0816ac19acf5f7b2..71e7d899436d0a3e54c395a7ce8fee3b96a7f43d 100644 (file)
@@ -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,
index 5605114db88412f10ca448405c915a0fa10aa42a..9e021d26795cba4f7ebbf9f7c23c36cca4523e50 100644 (file)
@@ -28,6 +28,10 @@ RuntimeError
 spam
 SyntaxError
 spam
+IndentationError
+spam
+TabError
+spam
 SystemError
 (hard to reproduce)
 spam
index 7bc515c488613fd80164b80f5ca49b097a8b911a..06861dfb3064973abaeddc2f21458e7dc075df8c 100644 (file)
@@ -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", '<string>', 'exec')
+#except TabError: pass
+#else: raise TestFailed
+
 r(SystemError)
 print '(hard to reproduce)'
 
index ee40f216139c9112252c062ada000050a0159d14..b74de7fda5485412c489fb66b5f12917ce6a01e7 100644 (file)
@@ -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;
        }
 }
index 608737363a72ad0a6afb7b0b643881bb0723a1ec..d0df8cfb6903ed42a59c5389a847bca5de7e5232 100644 (file)
@@ -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
index 9ac1606ae8f08e8336a79b2c89586485f8af5928..9d090f1af9f2f9b98e155f51f2c9098d1ea494ce 100644 (file)
@@ -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;
index 0ef3fc00ff835e43f564e584e6464aae4a8f144c..d4ec34593a7448453a5d444895ee94ef3c38bf26 100644 (file)
@@ -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;
                                }
index f766ba5ef34ddbb7742b940076a877dd7d9a247b..a70e6c6a714c11db74954d0dfeedf65789218b43 100644 (file)
@@ -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.";
+
 
 \f
 /* 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,
index 74dffae74e8b97553619443a0fc0a7c807255c74..9cc80724f83693735f87bb84485d3e50066423f1 100644 (file)
@@ -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);
 }