comparison mercurial/revset.py @ 28871:6d6201fc5aae

parser: move alias declaration parser to common rule-set class The original _parsealiasdecl() function is split into common _builddecl() and revset-specific _parsealiasdecl(). And the original _parsealiasdecl() call is temporarily replaced by rules._builddecl(), which should be eliminated later. The doctests are mostly ported by using the dummy parse(), but the test for 'foo bar' is kept in _parsealiasdecl() as it checks if "pos != len(decl)" is working. Also, 'foo($1)' test is added to make sure the alias tokenizer can handle '$1' symbol, which is the only reason why we need _parsealiasdecl().
author Yuya Nishihara <yuya@tcha.org>
date Mon, 29 Feb 2016 17:54:03 +0900
parents 475dad3432fd
children 5f31d2248745
comparison
equal deleted inserted replaced
28870:475dad3432fd 28871:6d6201fc5aae
2235 syminitletters=_aliassyminitletters) 2235 syminitletters=_aliassyminitletters)
2236 2236
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):
2312 return tree 2255 return tree
2313 op = tree[0] 2256 op = tree[0]
2367 return _relabelaliasargs(tree, args) 2310 return _relabelaliasargs(tree, args)
2368 2311
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):
2375 # whether own `error` information is already shown or not. 2319 # whether own `error` information is already shown or not.
2376 # this avoids showing same warning multiple times at each `findaliases`. 2320 # this avoids showing same warning multiple times at each `findaliases`.
2380 '''Aliases like: 2324 '''Aliases like:
2381 2325
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)
2389 return 2334 return
2390 2335