Mercurial > public > mercurial-scm > hg
comparison mercurial/revset.py @ 23846:aac4a1a7920e
revset: parse alias declaration strictly by _parsealiasdecl
Before this patch, alias declaration is parsed by string base
operations: matching against "^([^(]+)\(([^)]+)\)$" and splitting by
",".
This overlooks many syntax errors like below (see the previous patch
introducing "_parsealiasdecl" for detail):
- un-closed parenthesis causes being treated as "alias symbol"
- symbol/function name aren't examined whether they are valid or not
- invalid argument list causes unexpected argument names
To parse alias declaration strictly, this patch replaces parsing
implementation by "_parsealiasdecl".
This patch tests only one typical declaration error case, because
error detection itself is already tested in the doctest of
"_parsealiasdecl".
This also removes class property "args" and "error", because these are
certainly initialized in "revsetalias.__init__".
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Sat, 10 Jan 2015 23:18:11 +0900 |
parents | 0a7fd54d4e60 |
children | 71402bb8d8b2 |
comparison
equal
deleted
inserted
replaced
23845:0a7fd54d4e60 | 23846:aac4a1a7920e |
---|---|
2232 return (decl, None, None, _("invalid format")) | 2232 return (decl, None, None, _("invalid format")) |
2233 except error.ParseError, inst: | 2233 except error.ParseError, inst: |
2234 return (decl, None, None, parseerrordetail(inst)) | 2234 return (decl, None, None, parseerrordetail(inst)) |
2235 | 2235 |
2236 class revsetalias(object): | 2236 class revsetalias(object): |
2237 funcre = re.compile('^([^(]+)\(([^)]+)\)$') | |
2238 args = None | |
2239 | |
2240 # error message at parsing, or None | |
2241 error = None | |
2242 # whether own `error` information is already shown or not. | 2237 # whether own `error` information is already shown or not. |
2243 # this avoids showing same warning multiple times at each `findaliases`. | 2238 # this avoids showing same warning multiple times at each `findaliases`. |
2244 warned = False | 2239 warned = False |
2245 | 2240 |
2246 def __init__(self, name, value): | 2241 def __init__(self, name, value): |
2247 '''Aliases like: | 2242 '''Aliases like: |
2248 | 2243 |
2249 h = heads(default) | 2244 h = heads(default) |
2250 b($1) = ancestors($1) - ancestors(default) | 2245 b($1) = ancestors($1) - ancestors(default) |
2251 ''' | 2246 ''' |
2252 m = self.funcre.search(name) | 2247 self.name, self.tree, self.args, self.error = _parsealiasdecl(name) |
2253 if m: | 2248 if self.error: |
2254 self.name = m.group(1) | 2249 self.error = _('failed to parse the declaration of revset alias' |
2255 self.tree = ('func', ('symbol', m.group(1))) | 2250 ' "%s": %s') % (self.name, self.error) |
2256 self.args = [x.strip() for x in m.group(2).split(',')] | 2251 return |
2252 | |
2253 if self.args: | |
2257 for arg in self.args: | 2254 for arg in self.args: |
2258 # _aliasarg() is an unknown symbol only used separate | 2255 # _aliasarg() is an unknown symbol only used separate |
2259 # alias argument placeholders from regular strings. | 2256 # alias argument placeholders from regular strings. |
2260 value = value.replace(arg, '_aliasarg(%r)' % (arg,)) | 2257 value = value.replace(arg, '_aliasarg(%r)' % (arg,)) |
2261 else: | |
2262 self.name = name | |
2263 self.tree = ('symbol', name) | |
2264 | 2258 |
2265 try: | 2259 try: |
2266 self.replacement, pos = parse(value) | 2260 self.replacement, pos = parse(value) |
2267 if pos != len(value): | 2261 if pos != len(value): |
2268 raise error.ParseError(_('invalid token'), pos) | 2262 raise error.ParseError(_('invalid token'), pos) |