1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
from rpython.rlib.objectmodel import specialize
from pypy.interpreter.unicodehelper import _str_decode_utf8_slowpath
def wrap_pos(space, num):
if num <= 0:
return space.w_None
return space.newint(num)
@specialize.memo()
def make_replace_error_handler(space):
def replace_error_handler(errors, encoding, msg, w_s, startpos, endpos):
return b'\xef\xbf\xbd', endpos, 'b', space.bytes_w(w_s), w_s
return replace_error_handler
def _adjust_offset(space, offset, text, unilength):
if offset > len(text):
offset = unilength
elif offset >= 1:
offset = offset - 1 # 1-based to 0-based
assert offset >= 0
# slightly inefficient, call the decoder for text[:offset] too
s = text[:offset]
w_s = space.newbytes(s)
_, offset, _ = _str_decode_utf8_slowpath(space,
s, w_s, 'replace', False, make_replace_error_handler(space),
True)
offset += 1 # convert to 1-based
else:
offset = 0
return offset
class SyntaxError(Exception):
"""Base class for exceptions raised by the parser."""
def __init__(self, msg, lineno=0, offset=0, text=None, filename=None,
end_lineno=0, end_offset=0):
self.msg = msg
self.lineno = lineno
# NB: offset and end_offset are 1-based indexes into the bytes source
self.offset = offset
self.text = text
self.filename = filename
self.end_lineno = end_lineno
self.end_offset = end_offset
@staticmethod
def fromast(msg, node, filename=None):
return SyntaxError(msg, node.lineno, node.col_offset + 1,
filename=filename,
end_lineno=node.end_lineno,
end_offset=node.end_col_offset + 1)
def find_sourceline_and_wrap_info(self, space, source=None, filename=None):
""" search for the line of input that caused the error and then return
a wrapped tuple that can be used to construct a wrapped SyntaxError.
Optionally pass source, to get better error messages for the case where
this instance was constructed without a source line (.text
attribute)"""
text = self.text
if text is None and source is not None and self.lineno:
lines = source.splitlines(True)
text = lines[self.lineno - 1]
w_text = w_filename = space.w_None
w_lineno = space.newint(self.lineno)
if filename is None:
filename = self.filename
if filename is not None:
w_filename = space.newfilename(filename)
if text is None:
w_text = space.appexec([w_filename, w_lineno],
"""(filename, lineno):
try:
with open(filename) as f:
for _ in range(lineno - 1):
f.readline()
return f.readline()
except: # we can't allow any exceptions here!
return None""")
offset = self.offset
end_offset = self.end_offset
if text is not None:
# text may not be UTF-8 in case of decoding errors.
# adjust the encoded text offset to a decoded offset
# XXX do the right thing about continuation lines, which
# XXX are their own fun, sometimes giving offset >
# XXX len(text) for example (right now, avoid crashing)
# this also converts the byte-based self.offset to a
# codepoint-based index into the decoded unicode-version of
# self.text
replacedtext, unilength, _ = _str_decode_utf8_slowpath(space,
text, space.newbytes(text), 'replace', False, make_replace_error_handler(space), True)
offset = _adjust_offset(space, offset, text, unilength)
# XXX this is wrong if end_lineno != lineno
end_offset = _adjust_offset(space, end_offset, text, unilength)
w_text = space.newutf8(replacedtext, unilength)
return space.newtuple([
space.newtext(self.msg),
space.newtuple([
w_filename, w_lineno, wrap_pos(space, offset),
w_text, wrap_pos(space, self.end_lineno),
wrap_pos(space, end_offset)])])
def __str__(self):
return "%s at pos (%d, %d) in %r" % (
self.__class__.__name__, self.lineno, self.offset, self.text)
class IndentationError(SyntaxError):
pass
class TabError(IndentationError):
def __init__(self, lineno=0, offset=0, text=None, filename=None,
end_lineno=0, end_offset=0):
msg = "inconsistent use of tabs and spaces in indentation"
IndentationError.__init__(
self, msg, lineno, offset, text, filename, end_lineno, end_offset)
class ASTError(Exception):
def __init__(self, msg, ast_node):
self.msg = msg
self.ast_node = ast_node
class TokenError(SyntaxError):
def __init__(self, msg, line, lineno, column, tokens, end_lineno=0, end_offset=0):
SyntaxError.__init__(self, msg, lineno, column, line,
end_lineno=end_lineno, end_offset=end_offset)
self.tokens = tokens
class TokenIndentationError(IndentationError):
def __init__(self, msg, line, lineno, column, tokens):
SyntaxError.__init__(self, msg, lineno, column, line)
self.tokens = tokens
|