Show More
@@ -264,3 +264,108 b' class basealiasrules(object):' | |||||
264 | def _getlist(tree): |
|
264 | def _getlist(tree): | |
265 | """Extract a list of arguments from parsed tree""" |
|
265 | """Extract a list of arguments from parsed tree""" | |
266 | raise NotImplementedError |
|
266 | raise NotImplementedError | |
|
267 | ||||
|
268 | @classmethod | |||
|
269 | def _builddecl(cls, decl): | |||
|
270 | """Parse an alias declaration into ``(name, tree, args, errorstr)`` | |||
|
271 | ||||
|
272 | This function analyzes the parsed tree. The parsing rule is provided | |||
|
273 | by ``_parsedecl()``. | |||
|
274 | ||||
|
275 | - ``name``: of declared alias (may be ``decl`` itself at error) | |||
|
276 | - ``tree``: parse result (or ``None`` at error) | |||
|
277 | - ``args``: list of argument names (or None for symbol declaration) | |||
|
278 | - ``errorstr``: detail about detected error (or None) | |||
|
279 | ||||
|
280 | >>> sym = lambda x: ('symbol', x) | |||
|
281 | >>> symlist = lambda *xs: ('list',) + tuple(sym(x) for x in xs) | |||
|
282 | >>> func = lambda n, a: ('func', sym(n), a) | |||
|
283 | >>> parsemap = { | |||
|
284 | ... 'foo': sym('foo'), | |||
|
285 | ... '$foo': sym('$foo'), | |||
|
286 | ... 'foo::bar': ('dagrange', sym('foo'), sym('bar')), | |||
|
287 | ... 'foo()': func('foo', None), | |||
|
288 | ... '$foo()': func('$foo', None), | |||
|
289 | ... 'foo($1, $2)': func('foo', symlist('$1', '$2')), | |||
|
290 | ... 'foo(bar_bar, baz.baz)': | |||
|
291 | ... func('foo', symlist('bar_bar', 'baz.baz')), | |||
|
292 | ... 'foo(bar($1, $2))': | |||
|
293 | ... func('foo', func('bar', symlist('$1', '$2'))), | |||
|
294 | ... 'foo($1, $2, nested($1, $2))': | |||
|
295 | ... func('foo', (symlist('$1', '$2') + | |||
|
296 | ... (func('nested', symlist('$1', '$2')),))), | |||
|
297 | ... 'foo("bar")': func('foo', ('string', 'bar')), | |||
|
298 | ... 'foo($1, $2': error.ParseError('unexpected token: end', 10), | |||
|
299 | ... 'foo("bar': error.ParseError('unterminated string', 5), | |||
|
300 | ... 'foo($1, $2, $1)': func('foo', symlist('$1', '$2', '$1')), | |||
|
301 | ... } | |||
|
302 | >>> def parse(expr): | |||
|
303 | ... x = parsemap[expr] | |||
|
304 | ... if isinstance(x, Exception): | |||
|
305 | ... raise x | |||
|
306 | ... return x | |||
|
307 | >>> def getlist(tree): | |||
|
308 | ... if not tree: | |||
|
309 | ... return [] | |||
|
310 | ... if tree[0] == 'list': | |||
|
311 | ... return list(tree[1:]) | |||
|
312 | ... return [tree] | |||
|
313 | >>> class aliasrules(basealiasrules): | |||
|
314 | ... _parsedecl = staticmethod(parse) | |||
|
315 | ... _getlist = staticmethod(getlist) | |||
|
316 | >>> builddecl = aliasrules._builddecl | |||
|
317 | >>> builddecl('foo') | |||
|
318 | ('foo', ('symbol', 'foo'), None, None) | |||
|
319 | >>> builddecl('$foo') | |||
|
320 | ('$foo', None, None, "'$' not for alias arguments") | |||
|
321 | >>> builddecl('foo::bar') | |||
|
322 | ('foo::bar', None, None, 'invalid format') | |||
|
323 | >>> builddecl('foo()') | |||
|
324 | ('foo', ('func', ('symbol', 'foo')), [], None) | |||
|
325 | >>> builddecl('$foo()') | |||
|
326 | ('$foo()', None, None, "'$' not for alias arguments") | |||
|
327 | >>> builddecl('foo($1, $2)') | |||
|
328 | ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None) | |||
|
329 | >>> builddecl('foo(bar_bar, baz.baz)') | |||
|
330 | ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None) | |||
|
331 | >>> builddecl('foo($1, $2, nested($1, $2))') | |||
|
332 | ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list') | |||
|
333 | >>> builddecl('foo(bar($1, $2))') | |||
|
334 | ('foo(bar($1, $2))', None, None, 'invalid argument list') | |||
|
335 | >>> builddecl('foo("bar")') | |||
|
336 | ('foo("bar")', None, None, 'invalid argument list') | |||
|
337 | >>> builddecl('foo($1, $2') | |||
|
338 | ('foo($1, $2', None, None, 'at 10: unexpected token: end') | |||
|
339 | >>> builddecl('foo("bar') | |||
|
340 | ('foo("bar', None, None, 'at 5: unterminated string') | |||
|
341 | >>> builddecl('foo($1, $2, $1)') | |||
|
342 | ('foo', None, None, 'argument names collide with each other') | |||
|
343 | """ | |||
|
344 | try: | |||
|
345 | tree = cls._parsedecl(decl) | |||
|
346 | except error.ParseError as inst: | |||
|
347 | return (decl, None, None, parseerrordetail(inst)) | |||
|
348 | ||||
|
349 | if tree[0] == cls._symbolnode: | |||
|
350 | # "name = ...." style | |||
|
351 | name = tree[1] | |||
|
352 | if name.startswith('$'): | |||
|
353 | return (decl, None, None, _("'$' not for alias arguments")) | |||
|
354 | return (name, tree, None, None) | |||
|
355 | ||||
|
356 | if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode: | |||
|
357 | # "name(arg, ....) = ...." style | |||
|
358 | name = tree[1][1] | |||
|
359 | if name.startswith('$'): | |||
|
360 | return (decl, None, None, _("'$' not for alias arguments")) | |||
|
361 | args = [] | |||
|
362 | for arg in cls._getlist(tree[2]): | |||
|
363 | if arg[0] != cls._symbolnode: | |||
|
364 | return (decl, None, None, _("invalid argument list")) | |||
|
365 | args.append(arg[1]) | |||
|
366 | if len(args) != len(set(args)): | |||
|
367 | return (name, None, None, | |||
|
368 | _("argument names collide with each other")) | |||
|
369 | return (name, tree[:2], args, None) | |||
|
370 | ||||
|
371 | return (decl, None, None, _("invalid format")) |
@@ -2237,75 +2237,18 b' def _tokenizealias(program, lookup=None)' | |||||
2237 | def _parsealiasdecl(decl): |
|
2237 | def _parsealiasdecl(decl): | |
2238 | """Parse alias declaration ``decl`` |
|
2238 | """Parse alias declaration ``decl`` | |
2239 |
|
2239 | |||
2240 | This returns ``(name, tree, args, errorstr)`` tuple: |
|
2240 | >>> _parsealiasdecl('foo($1)') | |
2241 |
|
2241 | ('func', ('symbol', 'foo'), ('symbol', '$1')) | ||
2242 | - ``name``: of declared alias (may be ``decl`` itself at error) |
|
|||
2243 | - ``tree``: parse result (or ``None`` at error) |
|
|||
2244 | - ``args``: list of alias argument names (or None for symbol declaration) |
|
|||
2245 | - ``errorstr``: detail about detected error (or None) |
|
|||
2246 |
|
||||
2247 | >>> _parsealiasdecl('foo') |
|
|||
2248 | ('foo', ('symbol', 'foo'), None, None) |
|
|||
2249 | >>> _parsealiasdecl('$foo') |
|
|||
2250 | ('$foo', None, None, "'$' not for alias arguments") |
|
|||
2251 | >>> _parsealiasdecl('foo::bar') |
|
|||
2252 | ('foo::bar', None, None, 'invalid format') |
|
|||
2253 | >>> _parsealiasdecl('foo bar') |
|
2242 | >>> _parsealiasdecl('foo bar') | |
2254 | ('foo bar', None, None, 'at 4: invalid token') |
|
2243 | Traceback (most recent call last): | |
2255 | >>> _parsealiasdecl('foo()') |
|
2244 | ... | |
2256 | ('foo', ('func', ('symbol', 'foo')), [], None) |
|
2245 | ParseError: ('invalid token', 4) | |
2257 | >>> _parsealiasdecl('$foo()') |
|
|||
2258 | ('$foo()', None, None, "'$' not for alias arguments") |
|
|||
2259 | >>> _parsealiasdecl('foo($1, $2)') |
|
|||
2260 | ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None) |
|
|||
2261 | >>> _parsealiasdecl('foo(bar_bar, baz.baz)') |
|
|||
2262 | ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None) |
|
|||
2263 | >>> _parsealiasdecl('foo($1, $2, nested($1, $2))') |
|
|||
2264 | ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list') |
|
|||
2265 | >>> _parsealiasdecl('foo(bar($1, $2))') |
|
|||
2266 | ('foo(bar($1, $2))', None, None, 'invalid argument list') |
|
|||
2267 | >>> _parsealiasdecl('foo("string")') |
|
|||
2268 | ('foo("string")', None, None, 'invalid argument list') |
|
|||
2269 | >>> _parsealiasdecl('foo($1, $2') |
|
|||
2270 | ('foo($1, $2', None, None, 'at 10: unexpected token: end') |
|
|||
2271 | >>> _parsealiasdecl('foo("string') |
|
|||
2272 | ('foo("string', None, None, 'at 5: unterminated string') |
|
|||
2273 | >>> _parsealiasdecl('foo($1, $2, $1)') |
|
|||
2274 | ('foo', None, None, 'argument names collide with each other') |
|
|||
2275 | """ |
|
2246 | """ | |
2276 | p = parser.parser(elements) |
|
2247 | p = parser.parser(elements) | |
2277 | try: |
|
2248 | tree, pos = p.parse(_tokenizealias(decl)) | |
2278 | tree, pos = p.parse(_tokenizealias(decl)) |
|
2249 | if pos != len(decl): | |
2279 | if (pos != len(decl)): |
|
2250 | raise error.ParseError(_('invalid token'), pos) | |
2280 | raise error.ParseError(_('invalid token'), pos) |
|
2251 | return parser.simplifyinfixops(tree, ('list',)) | |
2281 | tree = parser.simplifyinfixops(tree, ('list',)) |
|
|||
2282 | except error.ParseError as inst: |
|
|||
2283 | return (decl, None, None, parser.parseerrordetail(inst)) |
|
|||
2284 |
|
||||
2285 | if True: # XXX to be removed |
|
|||
2286 | if tree[0] == 'symbol': |
|
|||
2287 | # "name = ...." style |
|
|||
2288 | name = tree[1] |
|
|||
2289 | if name.startswith('$'): |
|
|||
2290 | return (decl, None, None, _("'$' not for alias arguments")) |
|
|||
2291 | return (name, tree, None, None) |
|
|||
2292 |
|
||||
2293 | if tree[0] == 'func' and tree[1][0] == 'symbol': |
|
|||
2294 | # "name(arg, ....) = ...." style |
|
|||
2295 | name = tree[1][1] |
|
|||
2296 | if name.startswith('$'): |
|
|||
2297 | return (decl, None, None, _("'$' not for alias arguments")) |
|
|||
2298 | args = [] |
|
|||
2299 | for arg in getlist(tree[2]): |
|
|||
2300 | if arg[0] != 'symbol': |
|
|||
2301 | return (decl, None, None, _("invalid argument list")) |
|
|||
2302 | args.append(arg[1]) |
|
|||
2303 | if len(args) != len(set(args)): |
|
|||
2304 | return (name, None, None, |
|
|||
2305 | _("argument names collide with each other")) |
|
|||
2306 | return (name, tree[:2], args, None) |
|
|||
2307 |
|
||||
2308 | return (decl, None, None, _("invalid format")) |
|
|||
2309 |
|
2252 | |||
2310 | def _relabelaliasargs(tree, args): |
|
2253 | def _relabelaliasargs(tree, args): | |
2311 | if not isinstance(tree, tuple): |
|
2254 | if not isinstance(tree, tuple): | |
@@ -2369,6 +2312,7 b' def _parsealiasdefn(defn, args):' | |||||
2369 | class _aliasrules(parser.basealiasrules): |
|
2312 | class _aliasrules(parser.basealiasrules): | |
2370 | """Parsing and expansion rule set of revset aliases""" |
|
2313 | """Parsing and expansion rule set of revset aliases""" | |
2371 | _section = _('revset alias') |
|
2314 | _section = _('revset alias') | |
|
2315 | _parsedecl = staticmethod(_parsealiasdecl) | |||
2372 | _getlist = staticmethod(getlist) |
|
2316 | _getlist = staticmethod(getlist) | |
2373 |
|
2317 | |||
2374 | class revsetalias(object): |
|
2318 | class revsetalias(object): | |
@@ -2382,7 +2326,8 b' class revsetalias(object):' | |||||
2382 | h = heads(default) |
|
2326 | h = heads(default) | |
2383 | b($1) = ancestors($1) - ancestors(default) |
|
2327 | b($1) = ancestors($1) - ancestors(default) | |
2384 | ''' |
|
2328 | ''' | |
2385 | self.name, self.tree, self.args, self.error = _parsealiasdecl(name) |
|
2329 | r = _aliasrules._builddecl(name) | |
|
2330 | self.name, self.tree, self.args, self.error = r | |||
2386 | if self.error: |
|
2331 | if self.error: | |
2387 | self.error = _('failed to parse the declaration of revset alias' |
|
2332 | self.error = _('failed to parse the declaration of revset alias' | |
2388 | ' "%s": %s') % (self.name, self.error) |
|
2333 | ' "%s": %s') % (self.name, self.error) |
General Comments 0
You need to be logged in to leave comments.
Login now