Project

General

Profile

« Previous | Next » 

Revision 76

Refactored xpath.parse() to use a nested function instead of a class extending Parser

View differences:

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