__init__.py
2.23 KB
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
# coding: utf-8
import io, re
from .. import ParseError
##
## insert INDENT/DEDENT
##
_indent = re.compile(r"^\s*")
def indedent (text, indent="↦", dedent="↤") :
"insert INDENT/DEDENT tokens into text"
stack = [0]
src = io.StringIO(text.rstrip() + "\n")
out = io.StringIO()
for i, line in enumerate(src) :
if line.rstrip() :
width = _indent.match(line).end()
if width > stack[-1] :
out.write(indent)
stack.append(width)
elif width < stack[-1] :
while width < stack[-1] :
out.write(dedent)
stack.pop()
if width != stack[-1] :
raise IndentationError("line %s" % (i+1))
out.write(line)
while stack[-1] > 0 :
out.write(dedent)
stack.pop()
return out.getvalue()
##
## base parser
##
_errre = re.compile(r"^.*?error at line ([0-9]+), col ([0-9]+):[ \t]*"
"((.|\n)*)$", re.I|re.A)
class BaseParser (object) :
@classmethod
def make_parser (cls) :
def parse (source) :
if isinstance(source, str) :
return cls().parse(source, "<string>")
else :
return cls().parse(source.read(), getattr(source, "name", "<string>"))
return parse
def init (self, parser) :
pass
def parse (self, source, path) :
self.source = source
self.path = path
self.parser = parser = self.__parser__(indedent(source))
self.init(parser)
try :
do_parse = getattr(parser, parser.__default__, "INPUT")
result = do_parse()
if result is parser.NoMatch or parser.p_peek() is not None:
parser.p_raise()
return result
except parser.ParserError as err :
self._raise(err, path)
def _raise (self, error, path=None) :
message = str(error)
match = _errre.match(message)
if match :
raise ParseError(match.group(3),
lno=int(match.group(1)),
cno=int(match.group(2)),
path=path)
else :
raise ParseError(message, path=path)