100 if parent in reachable: |
100 if parent in reachable: |
101 reachable.add(rev) |
101 reachable.add(rev) |
102 return baseset(sorted(reachable)) |
102 return baseset(sorted(reachable)) |
103 |
103 |
104 elements = { |
104 elements = { |
105 "(": (20, ("group", 1, ")"), ("func", 1, ")")), |
105 "(": (21, ("group", 1, ")"), ("func", 1, ")")), |
|
106 "##": (20, None, ("_concat", 20)), |
106 "~": (18, None, ("ancestor", 18)), |
107 "~": (18, None, ("ancestor", 18)), |
107 "^": (18, None, ("parent", 18), ("parentpost", 18)), |
108 "^": (18, None, ("parent", 18), ("parentpost", 18)), |
108 "-": (5, ("negate", 19), ("minus", 5)), |
109 "-": (5, ("negate", 19), ("minus", 5)), |
109 "::": (17, ("dagrangepre", 17), ("dagrange", 17), |
110 "::": (17, ("dagrangepre", 17), ("dagrange", 17), |
110 ("dagrangepost", 17)), |
111 ("dagrangepost", 17)), |
145 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully |
146 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully |
146 yield ('::', None, pos) |
147 yield ('::', None, pos) |
147 pos += 1 # skip ahead |
148 pos += 1 # skip ahead |
148 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully |
149 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully |
149 yield ('..', None, pos) |
150 yield ('..', None, pos) |
|
151 pos += 1 # skip ahead |
|
152 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully |
|
153 yield ('##', None, pos) |
150 pos += 1 # skip ahead |
154 pos += 1 # skip ahead |
151 elif c in "():,-|&+!~^": # handle simple operators |
155 elif c in "():,-|&+!~^": # handle simple operators |
152 yield (c, None, pos) |
156 yield (c, None, pos) |
153 elif (c in '"\'' or c == 'r' and |
157 elif (c in '"\'' or c == 'r' and |
154 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings |
158 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings |
2154 ) % (name, alias.error) |
2158 ) % (name, alias.error) |
2155 showwarning(_('warning: %s\n') % (msg)) |
2159 showwarning(_('warning: %s\n') % (msg)) |
2156 alias.warned = True |
2160 alias.warned = True |
2157 return tree |
2161 return tree |
2158 |
2162 |
|
2163 def foldconcat(tree): |
|
2164 """Fold elements to be concatenated by `##` |
|
2165 """ |
|
2166 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'): |
|
2167 return tree |
|
2168 if tree[0] == '_concat': |
|
2169 pending = [tree] |
|
2170 l = [] |
|
2171 while pending: |
|
2172 e = pending.pop() |
|
2173 if e[0] == '_concat': |
|
2174 pending.extend(reversed(e[1:])) |
|
2175 elif e[0] in ('string', 'symbol'): |
|
2176 l.append(e[1]) |
|
2177 else: |
|
2178 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0]) |
|
2179 raise error.ParseError(msg) |
|
2180 return ('string', ''.join(l)) |
|
2181 else: |
|
2182 return tuple(foldconcat(t) for t in tree) |
|
2183 |
2159 def parse(spec, lookup=None): |
2184 def parse(spec, lookup=None): |
2160 p = parser.parser(tokenize, elements) |
2185 p = parser.parser(tokenize, elements) |
2161 return p.parse(spec, lookup=lookup) |
2186 return p.parse(spec, lookup=lookup) |
2162 |
2187 |
2163 def match(ui, spec, repo=None): |
2188 def match(ui, spec, repo=None): |
2169 tree, pos = parse(spec, lookup) |
2194 tree, pos = parse(spec, lookup) |
2170 if (pos != len(spec)): |
2195 if (pos != len(spec)): |
2171 raise error.ParseError(_("invalid token"), pos) |
2196 raise error.ParseError(_("invalid token"), pos) |
2172 if ui: |
2197 if ui: |
2173 tree = findaliases(ui, tree, showwarning=ui.warn) |
2198 tree = findaliases(ui, tree, showwarning=ui.warn) |
|
2199 tree = foldconcat(tree) |
2174 weight, tree = optimize(tree, True) |
2200 weight, tree = optimize(tree, True) |
2175 def mfunc(repo, subset): |
2201 def mfunc(repo, subset): |
2176 if util.safehasattr(subset, 'isascending'): |
2202 if util.safehasattr(subset, 'isascending'): |
2177 result = getset(repo, subset, tree) |
2203 result = getset(repo, subset, tree) |
2178 else: |
2204 else: |