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