Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revset.py @ 23993:eedade006458
revset: introduce _parsealiasdefn to parse alias definitions strictly
This patch introduces "_parsealiasdefn" to parse alias definitions
strictly. For example, it can avoid problems below, which current
implementation can't.
- the shorter name argument breaks referring the longer name one in
the definition, if the former is completely prefix of the latter
for example, the alias definition "foo($1, $10) = $1 or $10" is
parsed as "_aliasarg('$1') or _aliasarg('$1')0" and causes parse
error, because tail "0" of "_aliasarg('$1')0" is invalid.
- argument names in the quoted string are broken
for example, the definition "foo($1) = $1 or desc('$1')" is parsed
as "_aliasarg('$1') or desc('_aliasarg(\'$1\')')" and causes
unexpected description matching against not '$1' but '_aliasarg(\'$1\')'.
To decrease complication of patch, current implementation for alias
definitions is replaced by "_parsealiasdefn" in the subsequent
patch. This patch just introduces it.
This patch defines "_parsealiasdefn" not as a method of "revsetalias"
class but as a one of "revset" module, because of ease of testing by
doctest.
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Mon, 02 Feb 2015 23:07:04 +0900 |
parents | eeb5d5ab14a6 |
children | 8a2156780839 |
comparison
equal
deleted
inserted
replaced
23992:db85e454fccc | 23993:eedade006458 |
---|---|
2240 | 2240 |
2241 return (decl, None, None, _("invalid format")) | 2241 return (decl, None, None, _("invalid format")) |
2242 except error.ParseError, inst: | 2242 except error.ParseError, inst: |
2243 return (decl, None, None, parseerrordetail(inst)) | 2243 return (decl, None, None, parseerrordetail(inst)) |
2244 | 2244 |
2245 def _parsealiasdefn(defn, args): | |
2246 """Parse alias definition ``defn`` | |
2247 | |
2248 This function also replaces alias argument references in the | |
2249 specified definition by ``_aliasarg(ARGNAME)``. | |
2250 | |
2251 ``args`` is a list of alias argument names, or None if the alias | |
2252 is declared as a symbol. | |
2253 | |
2254 This returns "tree" as parsing result. | |
2255 | |
2256 >>> args = ['$1', '$2', 'foo'] | |
2257 >>> print prettyformat(_parsealiasdefn('$1 or foo', args)) | |
2258 (or | |
2259 (func | |
2260 ('symbol', '_aliasarg') | |
2261 ('string', '$1')) | |
2262 (func | |
2263 ('symbol', '_aliasarg') | |
2264 ('string', 'foo'))) | |
2265 >>> try: | |
2266 ... _parsealiasdefn('$1 or $bar', args) | |
2267 ... except error.ParseError, inst: | |
2268 ... print parseerrordetail(inst) | |
2269 at 6: '$' not for alias arguments | |
2270 >>> args = ['$1', '$10', 'foo'] | |
2271 >>> print prettyformat(_parsealiasdefn('$10 or foobar', args)) | |
2272 (or | |
2273 (func | |
2274 ('symbol', '_aliasarg') | |
2275 ('string', '$10')) | |
2276 ('symbol', 'foobar')) | |
2277 >>> print prettyformat(_parsealiasdefn('"$1" or "foo"', args)) | |
2278 (or | |
2279 ('string', '$1') | |
2280 ('string', 'foo')) | |
2281 """ | |
2282 def tokenizedefn(program, lookup=None): | |
2283 if args: | |
2284 argset = set(args) | |
2285 else: | |
2286 argset = set() | |
2287 | |
2288 for t, value, pos in _tokenizealias(program, lookup=lookup): | |
2289 if t == 'symbol': | |
2290 if value in argset: | |
2291 # emulate tokenization of "_aliasarg('ARGNAME')": | |
2292 # "_aliasarg()" is an unknown symbol only used separate | |
2293 # alias argument placeholders from regular strings. | |
2294 yield ('symbol', '_aliasarg', pos) | |
2295 yield ('(', None, pos) | |
2296 yield ('string', value, pos) | |
2297 yield (')', None, pos) | |
2298 continue | |
2299 elif value.startswith('$'): | |
2300 raise error.ParseError(_("'$' not for alias arguments"), | |
2301 pos) | |
2302 yield (t, value, pos) | |
2303 | |
2304 p = parser.parser(tokenizedefn, elements) | |
2305 tree, pos = p.parse(defn) | |
2306 if pos != len(defn): | |
2307 raise error.ParseError(_('invalid token'), pos) | |
2308 return tree | |
2309 | |
2245 class revsetalias(object): | 2310 class revsetalias(object): |
2246 # whether own `error` information is already shown or not. | 2311 # whether own `error` information is already shown or not. |
2247 # this avoids showing same warning multiple times at each `findaliases`. | 2312 # this avoids showing same warning multiple times at each `findaliases`. |
2248 warned = False | 2313 warned = False |
2249 | 2314 |