|
1 # fileset.py - file set queries for mercurial |
|
2 # |
|
3 # Copyright 2010 Matt Mackall <mpm@selenic.com> |
|
4 # |
|
5 # This software may be used and distributed according to the terms of the |
|
6 # GNU General Public License version 2 or any later version. |
|
7 |
|
8 import parser, error |
|
9 from i18n import _ |
|
10 |
|
11 elements = { |
|
12 "(": (20, ("group", 1, ")"), ("func", 1, ")")), |
|
13 "-": (5, ("negate", 19), ("minus", 5)), |
|
14 "not": (10, ("not", 10)), |
|
15 "!": (10, ("not", 10)), |
|
16 "and": (5, None, ("and", 5)), |
|
17 "&": (5, None, ("and", 5)), |
|
18 "or": (4, None, ("or", 4)), |
|
19 "|": (4, None, ("or", 4)), |
|
20 "+": (4, None, ("or", 4)), |
|
21 ",": (2, None, ("list", 2)), |
|
22 ")": (0, None, None), |
|
23 "symbol": (0, ("symbol",), None), |
|
24 "string": (0, ("string",), None), |
|
25 "end": (0, None, None), |
|
26 } |
|
27 |
|
28 keywords = set(['and', 'or', 'not']) |
|
29 |
|
30 def tokenize(program): |
|
31 pos, l = 0, len(program) |
|
32 while pos < l: |
|
33 c = program[pos] |
|
34 if c.isspace(): # skip inter-token whitespace |
|
35 pass |
|
36 elif c in "(),-|&+!": # handle simple operators |
|
37 yield (c, None, pos) |
|
38 elif (c in '"\'' or c == 'r' and |
|
39 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings |
|
40 if c == 'r': |
|
41 pos += 1 |
|
42 c = program[pos] |
|
43 decode = lambda x: x |
|
44 else: |
|
45 decode = lambda x: x.decode('string-escape') |
|
46 pos += 1 |
|
47 s = pos |
|
48 while pos < l: # find closing quote |
|
49 d = program[pos] |
|
50 if d == '\\': # skip over escaped characters |
|
51 pos += 2 |
|
52 continue |
|
53 if d == c: |
|
54 yield ('string', decode(program[s:pos]), s) |
|
55 break |
|
56 pos += 1 |
|
57 else: |
|
58 raise error.ParseError(_("unterminated string"), s) |
|
59 elif c.isalnum() or c in '.*{}[]?' or ord(c) > 127: # gather up a symbol/keyword |
|
60 s = pos |
|
61 pos += 1 |
|
62 while pos < l: # find end of symbol |
|
63 d = program[pos] |
|
64 if not (d.isalnum() or d in ".*{}[]?," or ord(d) > 127): |
|
65 break |
|
66 pos += 1 |
|
67 sym = program[s:pos] |
|
68 if sym in keywords: # operator keywords |
|
69 yield (sym, None, s) |
|
70 else: |
|
71 yield ('symbol', sym, s) |
|
72 pos -= 1 |
|
73 else: |
|
74 raise error.ParseError(_("syntax error"), pos) |
|
75 pos += 1 |
|
76 yield ('end', None, pos) |
|
77 |
|
78 parse = parser.parser(tokenize, elements).parse |
|
79 |