Revision 76
Added by Aaron Marcuse-Kubitza about 13 years ago
scripts/lib/Parser.py | ||
---|---|---|
5 | 5 |
class SyntaxException(Exception): pass |
6 | 6 |
|
7 | 7 |
class Parser: |
8 |
def __init__(self, string):
|
|
9 |
self._str = string
|
|
8 |
def __init__(self, str_):
|
|
9 |
self._str = str_
|
|
10 | 10 |
self._pos = 0 |
11 | 11 |
|
12 |
def parse(self): |
|
13 |
tree = self._main() |
|
12 |
def end(self): |
|
14 | 13 |
if not self._pos == len(self._str): self._syntax_err('End of string') |
15 |
return tree |
|
16 | 14 |
|
17 |
def _match_re(self, pattern, required=False): |
|
15 |
def str_(self, str_, required=False): |
|
16 |
end_pos = self._pos + len(str_) |
|
17 |
if self._str[self._pos:end_pos] == str_: |
|
18 |
self._pos = end_pos |
|
19 |
return True |
|
20 |
elif required: self._syntax_err(str_) |
|
21 |
else: return False |
|
22 |
|
|
23 |
def re(self, pattern, required=False): |
|
18 | 24 |
matcher = re.compile(pattern).match(self._str, self._pos) |
19 | 25 |
if matcher: |
20 | 26 |
self._pos = matcher.end(0) |
... | ... | |
22 | 28 |
elif required: self._syntax_err(pattern) |
23 | 29 |
else: return None |
24 | 30 |
|
25 |
def _match_str(self, string, required=False): |
|
26 |
end_pos = self._pos + len(string) |
|
27 |
if self._str[self._pos:end_pos] == string: |
|
28 |
self._pos = end_pos |
|
29 |
return True |
|
30 |
elif required: self._syntax_err(string) |
|
31 |
else: return False |
|
32 |
|
|
33 | 31 |
def _syntax_err(self, token): |
34 | 32 |
raise SyntaxException(self.__class__.__name__+' syntax error: '+token |
35 | 33 |
+' expected in '+self._str[self._pos:]) |
scripts/lib/xpath.py | ||
---|---|---|
34 | 34 |
len(elem.attrs[0]) == 1: return elem.attrs[0] |
35 | 35 |
else: return None |
36 | 36 |
|
37 |
class XpathParser(Parser): |
|
38 |
def _main(self): |
|
39 |
self._match_str('/') # optional leading / |
|
40 |
return self._path() |
|
37 |
def parse(str_): |
|
38 |
parser = Parser(str_) |
|
41 | 39 |
|
42 |
def _path(self):
|
|
40 |
def _path(): |
|
43 | 41 |
tree = [] |
44 | 42 |
trailing_slash = False |
45 | 43 |
while True: |
46 | 44 |
# Split path |
47 |
if self._match_str('{'):
|
|
45 |
if parser.str_('{'):
|
|
48 | 46 |
paths = [] |
49 | 47 |
while True: |
50 |
paths.append(tree + self._path())
|
|
51 |
if not self._match_str(','): break
|
|
52 |
self._match_str('}', required=True)
|
|
48 |
paths.append(tree + _path()) |
|
49 |
if not parser.str_(','): break
|
|
50 |
parser.str_('}', required=True)
|
|
53 | 51 |
tree = paths[0] # just use first subpath for now |
54 | 52 |
break # nothing allowed after split path |
55 | 53 |
|
56 |
elem = XpathElem(is_attr=self._match_str('@'),
|
|
57 |
name=self._match_re(r'[\w.*]+', required=True))
|
|
54 |
elem = XpathElem(is_attr=parser.str_('@'),
|
|
55 |
name=parser.re(r'[\w.*]+', required=True))
|
|
58 | 56 |
|
59 | 57 |
# Attrs |
60 |
if self._match_str('['):
|
|
58 |
if parser.str_('['):
|
|
61 | 59 |
elem.attrs = [] |
62 | 60 |
while True: |
63 |
path = self._path()
|
|
64 |
if self._match_str('='):
|
|
65 |
set_value(path, self._match_re(r'[\w.|]*'))
|
|
61 |
path = _path() |
|
62 |
if parser.str_('='):
|
|
63 |
set_value(path, parser.re(r'[\w.|]*'))
|
|
66 | 64 |
elem.attrs.append(path) |
67 |
if not self._match_str(','): break
|
|
68 |
self._match_str(']', required=True)
|
|
65 |
if not parser.str_(','): break
|
|
66 |
parser.str_(']', required=True)
|
|
69 | 67 |
|
70 |
elem.is_ptr = self._match_str('->')
|
|
68 |
elem.is_ptr = parser.str_('->')
|
|
71 | 69 |
tree.append(elem) |
72 | 70 |
|
73 | 71 |
# Lookahead assertion |
74 |
if self._match_str('('):
|
|
75 |
self._match_str('/', required=True) # next / is inside ()
|
|
76 |
path = self._path()
|
|
77 |
self._match_str(')', required=True)
|
|
72 |
if parser.str_('('):
|
|
73 |
parser.str_('/', required=True) # next / is inside ()
|
|
74 |
path = _path() |
|
75 |
parser.str_(')', required=True)
|
|
78 | 76 |
elem.attrs.append(path) |
79 | 77 |
tree += path |
80 | 78 |
|
81 |
if not self._match_str('/'): break
|
|
79 |
if not parser.str_('/'): break
|
|
82 | 80 |
|
83 | 81 |
# Expand * abbrs |
84 | 82 |
for i in reversed(xrange(len(tree))): |
... | ... | |
93 | 91 |
except IndexError: pass # no replacement elem |
94 | 92 |
|
95 | 93 |
return tree |
94 |
|
|
95 |
parser.str_('/') # optional leading / |
|
96 |
path = _path() |
|
97 |
parser.end() |
|
98 |
return path |
|
96 | 99 |
|
97 |
def parse(string): return XpathParser(string).parse() |
|
98 |
|
|
99 | 100 |
instance_level = 1 |
100 | 101 |
|
101 | 102 |
def obj(path): |
Also available in: Unified diff
Refactored xpath.parse() to use a nested function instead of a class extending Parser