Commits

Antonio Cuni committed 475b472

detect inconsisten use of tab and spaces and raise an inter-level TabError in that case. We still need to convert it to applevel

Comments (0)

Files changed (4)

pypy/interpreter/pyparser/error.py

 class IndentationError(SyntaxError):
     pass
 
+class TabError(IndentationError):
+    def __init__(self, lineno=0, offset=0, text=None, filename=None,
+                 lastlineno=0):
+        msg = "inconsistent use of tabs and spaces in indentation"
+        IndentationError.__init__(self, msg, lineno, offset, text, filename, lastlineno)
+
 class ASTError(Exception):
     def __init__(self, msg, ast_node ):
         self.msg = msg

pypy/interpreter/pyparser/pytokenize.py

     single_quoted[t] = t
 
 tabsize = 8
+alttabsize = 1
 
 # PYPY MODIFICATION: removed TokenError class as it's not needed here
 

pypy/interpreter/pyparser/pytokenizer.py

 from pypy.interpreter.pyparser import automata
 from pypy.interpreter.pyparser.pygram import tokens
 from pypy.interpreter.pyparser.pytoken import python_opmap
-from pypy.interpreter.pyparser.error import TokenError, TokenIndentationError
-from pypy.interpreter.pyparser.pytokenize import tabsize, whiteSpaceDFA, \
+from pypy.interpreter.pyparser.error import TokenError, TokenIndentationError, TabError
+from pypy.interpreter.pyparser.pytokenize import tabsize, alttabsize, whiteSpaceDFA, \
     triple_quoted, endDFAs, single_quoted, pseudoDFA
 from pypy.interpreter.astcompiler import consts
 
     contstr, needcont = '', 0
     contline = None
     indents = [0]
+    altindents = [0]
     last_comment = ''
     parenlevstart = (0, 0, "")
 
         elif parenlev == 0 and not continued:  # new statement
             if not line: break
             column = 0
+            altcolumn = 0
             while pos < max:                   # measure leading whitespace
-                if line[pos] == ' ': column = column + 1
-                elif line[pos] == '\t': column = (column/tabsize + 1)*tabsize
-                elif line[pos] == '\f': column = 0
-                else: break
+                if line[pos] == ' ':
+                    column = column + 1
+                    altcolumn = altcolumn + 1
+                elif line[pos] == '\t':
+                    column = (column/tabsize + 1)*tabsize
+                    altcolumn = (altcolumn/alttabsize + 1)*alttabsize
+                elif line[pos] == '\f':
+                    column = 0
+                else:
+                    break
                 pos = pos + 1
             if pos == max: break
 
                 # skip comments or blank lines
                 continue
 
-            if column > indents[-1]:           # count indents or dedents
+            if column == indents[-1]:
+                if altcolumn != altindents[-1]:
+                    raise TabError(lnum, pos, line)
+            elif column > indents[-1]:           # count indents or dedents
+                if altcolumn <= altindents[-1]:
+                    raise TabError(lnum, pos, line)
                 indents.append(column)
+                altindents.append(altcolumn)
                 token_list.append((tokens.INDENT, line[:pos], lnum, 0, line))
                 last_comment = ''
-            while column < indents[-1]:
-                indents = indents[:-1]
-                token_list.append((tokens.DEDENT, '', lnum, pos, line))
-                last_comment = ''
-            if column != indents[-1]:
-                err = "unindent does not match any outer indentation level"
-                raise TokenIndentationError(err, line, lnum, 0, token_list)
+            else:
+                while column < indents[-1]:
+                    indents = indents[:-1]
+                    altindents = altindents[:-1]
+                    token_list.append((tokens.DEDENT, '', lnum, pos, line))
+                    last_comment = ''
+                if column != indents[-1]:
+                    err = "unindent does not match any outer indentation level"
+                    raise TokenIndentationError(err, line, lnum, 0, token_list)
+                if altcolumn != altindents[-1]:
+                    raise TabError(lnum, pos, line)
 
         else:                                  # continued statement
             if not line:

pypy/interpreter/pyparser/test/test_pyparse.py

 import py
 from pypy.interpreter.pyparser import pyparse
 from pypy.interpreter.pyparser.pygram import syms, tokens
-from pypy.interpreter.pyparser.error import SyntaxError, IndentationError
+from pypy.interpreter.pyparser.error import SyntaxError, IndentationError, TabError
 from pypy.interpreter.astcompiler import consts
 
 
         assert exc.msg == "unindent does not match any outer indentation level"
         assert exc.lineno == 3
 
+    def test_taberror(self):
+        src = """
+if 1:
+        pass
+    \tpass
+"""
+        exc = py.test.raises(TabError, "self.parse(src)").value
+        assert exc.msg == "inconsistent use of tabs and spaces in indentation"
+        assert exc.lineno == 4
+        assert exc.offset == 5
+        assert exc.text == "    \tpass\n"
+
     def test_mac_newline(self):
         self.parse("this_is\ra_mac\rfile")