Show More
@@ -15,6 +15,8 b'' | |||||
15 | # an action is a tree node name, a tree label, and an optional match |
|
15 | # an action is a tree node name, a tree label, and an optional match | |
16 | # __call__(program) parses program into a labelled tree |
|
16 | # __call__(program) parses program into a labelled tree | |
17 |
|
17 | |||
|
18 | import error | |||
|
19 | ||||
18 | class parser(object): |
|
20 | class parser(object): | |
19 | def __init__(self, tokenizer, elements, methods=None): |
|
21 | def __init__(self, tokenizer, elements, methods=None): | |
20 | self._tokenizer = tokenizer |
|
22 | self._tokenizer = tokenizer | |
@@ -31,14 +33,15 b' class parser(object):' | |||||
31 | def _match(self, m): |
|
33 | def _match(self, m): | |
32 | 'make sure the tokenizer matches an end condition' |
|
34 | 'make sure the tokenizer matches an end condition' | |
33 | if self.current[0] != m: |
|
35 | if self.current[0] != m: | |
34 |
raise |
|
36 | raise error.ParseError("unexpected token: %s" % self.current[2], | |
|
37 | pos) | |||
35 | self._advance() |
|
38 | self._advance() | |
36 | def _parse(self, bind=0): |
|
39 | def _parse(self, bind=0): | |
37 | token, value = self._advance() |
|
40 | token, value, pos = self._advance() | |
38 | # handle prefix rules on current token |
|
41 | # handle prefix rules on current token | |
39 | prefix = self._elements[token][1] |
|
42 | prefix = self._elements[token][1] | |
40 | if not prefix: |
|
43 | if not prefix: | |
41 |
raise |
|
44 | raise error.ParseError("not a prefix: %s" % token, pos) | |
42 | if len(prefix) == 1: |
|
45 | if len(prefix) == 1: | |
43 | expr = (prefix[0], value) |
|
46 | expr = (prefix[0], value) | |
44 | else: |
|
47 | else: | |
@@ -51,7 +54,7 b' class parser(object):' | |||||
51 | self._match(prefix[2]) |
|
54 | self._match(prefix[2]) | |
52 | # gather tokens until we meet a lower binding strength |
|
55 | # gather tokens until we meet a lower binding strength | |
53 | while bind < self._elements[self.current[0]][0]: |
|
56 | while bind < self._elements[self.current[0]][0]: | |
54 | token, value = self._advance() |
|
57 | token, value, pos = self._advance() | |
55 | e = self._elements[token] |
|
58 | e = self._elements[token] | |
56 | # check for suffix - next token isn't a valid prefix |
|
59 | # check for suffix - next token isn't a valid prefix | |
57 | if len(e) == 4 and not self._elements[self.current[0]][1]: |
|
60 | if len(e) == 4 and not self._elements[self.current[0]][1]: | |
@@ -65,7 +68,7 b' class parser(object):' | |||||
65 | expr = (infix[0], expr, (None)) |
|
68 | expr = (infix[0], expr, (None)) | |
66 | else: |
|
69 | else: | |
67 | if not infix[0]: |
|
70 | if not infix[0]: | |
68 |
raise |
|
71 | raise error.ParseError("not an infix: %s" % token, pos) | |
69 | expr = (infix[0], expr, self._parse(infix[1])) |
|
72 | expr = (infix[0], expr, self._parse(infix[1])) | |
70 | if len(infix) == 3: |
|
73 | if len(infix) == 3: | |
71 | self._match(infix[2]) |
|
74 | self._match(infix[2]) |
@@ -6,7 +6,7 b'' | |||||
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | import re |
|
8 | import re | |
9 | import parser, util, hg |
|
9 | import parser, util, hg, error | |
10 | import match as _match |
|
10 | import match as _match | |
11 |
|
11 | |||
12 | elements = { |
|
12 | elements = { | |
@@ -40,13 +40,13 b' def tokenize(program):' | |||||
40 | if c.isspace(): # skip inter-token whitespace |
|
40 | if c.isspace(): # skip inter-token whitespace | |
41 | pass |
|
41 | pass | |
42 | elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully |
|
42 | elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully | |
43 | yield ('::', None) |
|
43 | yield ('::', None, pos) | |
44 | pos += 1 # skip ahead |
|
44 | pos += 1 # skip ahead | |
45 | elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully |
|
45 | elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully | |
46 | yield ('..', None) |
|
46 | yield ('..', None, pos) | |
47 | pos += 1 # skip ahead |
|
47 | pos += 1 # skip ahead | |
48 | elif c in "():,-|&+!": # handle simple operators |
|
48 | elif c in "():,-|&+!": # handle simple operators | |
49 | yield (c, None) |
|
49 | yield (c, None, pos) | |
50 | elif c in '"\'': # handle quoted strings |
|
50 | elif c in '"\'': # handle quoted strings | |
51 | pos += 1 |
|
51 | pos += 1 | |
52 | s = pos |
|
52 | s = pos | |
@@ -56,11 +56,11 b' def tokenize(program):' | |||||
56 | pos += 2 |
|
56 | pos += 2 | |
57 | continue |
|
57 | continue | |
58 | if d == c: |
|
58 | if d == c: | |
59 | yield ('string', program[s:pos].decode('string-escape')) |
|
59 | yield ('string', program[s:pos].decode('string-escape'), s) | |
60 | break |
|
60 | break | |
61 | pos += 1 |
|
61 | pos += 1 | |
62 | else: |
|
62 | else: | |
63 | raise "unterminated string" |
|
63 | raise error.ParseError("unterminated string", s) | |
64 | elif c.isalnum() or c in '.': # gather up a symbol/keyword |
|
64 | elif c.isalnum() or c in '.': # gather up a symbol/keyword | |
65 | s = pos |
|
65 | s = pos | |
66 | pos += 1 |
|
66 | pos += 1 | |
@@ -74,21 +74,21 b' def tokenize(program):' | |||||
74 | pos += 1 |
|
74 | pos += 1 | |
75 | sym = program[s:pos] |
|
75 | sym = program[s:pos] | |
76 | if sym in keywords: # operator keywords |
|
76 | if sym in keywords: # operator keywords | |
77 | yield (sym, None) |
|
77 | yield (sym, None, s) | |
78 | else: |
|
78 | else: | |
79 | yield ('symbol', sym) |
|
79 | yield ('symbol', sym, s) | |
80 | pos -= 1 |
|
80 | pos -= 1 | |
81 | else: |
|
81 | else: | |
82 |
raise "syntax error |
|
82 | raise error.ParseError("syntax error", pos) | |
83 | pos += 1 |
|
83 | pos += 1 | |
84 | yield ('end', None) |
|
84 | yield ('end', None, pos) | |
85 |
|
85 | |||
86 | # helpers |
|
86 | # helpers | |
87 |
|
87 | |||
88 | def getstring(x, err): |
|
88 | def getstring(x, err): | |
89 | if x[0] == 'string' or x[0] == 'symbol': |
|
89 | if x[0] == 'string' or x[0] == 'symbol': | |
90 | return x[1] |
|
90 | return x[1] | |
91 | raise err |
|
91 | raise error.ParseError(err) | |
92 |
|
92 | |||
93 | def getlist(x): |
|
93 | def getlist(x): | |
94 | if not x: |
|
94 | if not x: | |
@@ -100,12 +100,12 b' def getlist(x):' | |||||
100 | def getpair(x, err): |
|
100 | def getpair(x, err): | |
101 | l = getlist(x) |
|
101 | l = getlist(x) | |
102 | if len(l) != 2: |
|
102 | if len(l) != 2: | |
103 | raise err |
|
103 | raise error.ParseError(err) | |
104 | return l |
|
104 | return l | |
105 |
|
105 | |||
106 | def getset(repo, subset, x): |
|
106 | def getset(repo, subset, x): | |
107 | if not x: |
|
107 | if not x: | |
108 | raise "missing argument" |
|
108 | raise error.ParseError("missing argument") | |
109 | return methods[x[0]](repo, subset, *x[1:]) |
|
109 | return methods[x[0]](repo, subset, *x[1:]) | |
110 |
|
110 | |||
111 | # operator methods |
|
111 | # operator methods | |
@@ -124,7 +124,7 b' def stringset(repo, subset, x):' | |||||
124 |
|
124 | |||
125 | def symbolset(repo, subset, x): |
|
125 | def symbolset(repo, subset, x): | |
126 | if x in symbols: |
|
126 | if x in symbols: | |
127 | raise "can't use %s here" % x |
|
127 | raise error.ParseError("can't use %s here" % x) | |
128 | return stringset(repo, subset, x) |
|
128 | return stringset(repo, subset, x) | |
129 |
|
129 | |||
130 | def rangeset(repo, subset, x, y): |
|
130 | def rangeset(repo, subset, x, y): | |
@@ -147,12 +147,12 b' def notset(repo, subset, x):' | |||||
147 | return [r for r in subset if r not in s] |
|
147 | return [r for r in subset if r not in s] | |
148 |
|
148 | |||
149 | def listset(repo, subset, a, b): |
|
149 | def listset(repo, subset, a, b): | |
150 | raise "can't use a list in this context" |
|
150 | raise error.ParseError("can't use a list in this context") | |
151 |
|
151 | |||
152 | def func(repo, subset, a, b): |
|
152 | def func(repo, subset, a, b): | |
153 | if a[0] == 'symbol' and a[1] in symbols: |
|
153 | if a[0] == 'symbol' and a[1] in symbols: | |
154 | return symbols[a[1]](repo, subset, b) |
|
154 | return symbols[a[1]](repo, subset, b) | |
155 |
raise " |
|
155 | raise error.ParseError("not a function: %s" % a[1]) | |
156 |
|
156 | |||
157 | # functions |
|
157 | # functions | |
158 |
|
158 | |||
@@ -190,7 +190,7 b' def limit(repo, subset, x):' | |||||
190 | try: |
|
190 | try: | |
191 | lim = int(getstring(l[1], "limit wants a number")) |
|
191 | lim = int(getstring(l[1], "limit wants a number")) | |
192 | except ValueError: |
|
192 | except ValueError: | |
193 |
raise " |
|
193 | raise error.ParseError("limit expects a number") | |
194 | return getset(repo, subset, l[0])[:lim] |
|
194 | return getset(repo, subset, l[0])[:lim] | |
195 |
|
195 | |||
196 | def children(repo, subset, x): |
|
196 | def children(repo, subset, x): | |
@@ -216,7 +216,7 b' def ancestor(repo, subset, x):' | |||||
216 | a = getset(repo, subset, l[0]) |
|
216 | a = getset(repo, subset, l[0]) | |
217 | b = getset(repo, subset, l[1]) |
|
217 | b = getset(repo, subset, l[1]) | |
218 | if len(a) > 1 or len(b) > 1: |
|
218 | if len(a) > 1 or len(b) > 1: | |
219 |
raise " |
|
219 | raise error.ParseError("ancestor args must be single revisions") | |
220 | return [repo[a[0]].ancestor(repo[b[0]]).rev()] |
|
220 | return [repo[a[0]].ancestor(repo[b[0]]).rev()] | |
221 |
|
221 | |||
222 | def ancestors(repo, subset, x): |
|
222 | def ancestors(repo, subset, x): | |
@@ -231,7 +231,7 b' def descendants(repo, subset, x):' | |||||
231 |
|
231 | |||
232 | def follow(repo, subset, x): |
|
232 | def follow(repo, subset, x): | |
233 | if x: |
|
233 | if x: | |
234 | raise "follow takes no args" |
|
234 | raise error.ParseError("follow takes no args") | |
235 | p = repo['.'].rev() |
|
235 | p = repo['.'].rev() | |
236 | s = set(repo.changelog.ancestors(p)) | set([p]) |
|
236 | s = set(repo.changelog.ancestors(p)) | set([p]) | |
237 | return [r for r in subset if r in s] |
|
237 | return [r for r in subset if r in s] | |
@@ -336,7 +336,7 b' def removes(repo, subset, x):' | |||||
336 |
|
336 | |||
337 | def merge(repo, subset, x): |
|
337 | def merge(repo, subset, x): | |
338 | if x: |
|
338 | if x: | |
339 | raise "merge takes no args" |
|
339 | raise error.ParseError("merge takes no args") | |
340 | cl = repo.changelog |
|
340 | cl = repo.changelog | |
341 | return [r for r in subset if cl.parentrevs(r)[1] != -1] |
|
341 | return [r for r in subset if cl.parentrevs(r)[1] != -1] | |
342 |
|
342 | |||
@@ -390,7 +390,7 b' def sort(repo, subset, x):' | |||||
390 | elif k == '-date': |
|
390 | elif k == '-date': | |
391 | e.append(-c.date()[0]) |
|
391 | e.append(-c.date()[0]) | |
392 | else: |
|
392 | else: | |
393 | raise "unknown sort key %r" % k |
|
393 | raise error.ParseError("unknown sort key %r" % k) | |
394 | e.append(r) |
|
394 | e.append(r) | |
395 | l.append(e) |
|
395 | l.append(e) | |
396 | l.sort() |
|
396 | l.sort() |
General Comments 0
You need to be logged in to leave comments.
Login now