249 |
249 |
250 def __new__(cls): |
250 def __new__(cls): |
251 raise TypeError("'%s' is not instantiatable" % cls.__name__) |
251 raise TypeError("'%s' is not instantiatable" % cls.__name__) |
252 |
252 |
253 @staticmethod |
253 @staticmethod |
254 def _parsedecl(spec): |
254 def _parse(spec): |
255 """Parse an alias name and arguments""" |
255 """Parse an alias name, arguments and definition""" |
256 raise NotImplementedError |
|
257 |
|
258 @staticmethod |
|
259 def _parsedefn(spec): |
|
260 """Parse an alias definition""" |
|
261 raise NotImplementedError |
256 raise NotImplementedError |
262 |
257 |
263 @staticmethod |
258 @staticmethod |
264 def _getlist(tree): |
259 def _getlist(tree): |
265 """Extract a list of arguments from parsed tree""" |
260 """Extract a list of arguments from parsed tree""" |
268 @classmethod |
263 @classmethod |
269 def _builddecl(cls, decl): |
264 def _builddecl(cls, decl): |
270 """Parse an alias declaration into ``(name, tree, args, errorstr)`` |
265 """Parse an alias declaration into ``(name, tree, args, errorstr)`` |
271 |
266 |
272 This function analyzes the parsed tree. The parsing rule is provided |
267 This function analyzes the parsed tree. The parsing rule is provided |
273 by ``_parsedecl()``. |
268 by ``_parse()``. |
274 |
269 |
275 - ``name``: of declared alias (may be ``decl`` itself at error) |
270 - ``name``: of declared alias (may be ``decl`` itself at error) |
276 - ``tree``: parse result (or ``None`` at error) |
271 - ``tree``: parse result (or ``None`` at error) |
277 - ``args``: list of argument names (or None for symbol declaration) |
272 - ``args``: list of argument names (or None for symbol declaration) |
278 - ``errorstr``: detail about detected error (or None) |
273 - ``errorstr``: detail about detected error (or None) |
309 ... return [] |
304 ... return [] |
310 ... if tree[0] == 'list': |
305 ... if tree[0] == 'list': |
311 ... return list(tree[1:]) |
306 ... return list(tree[1:]) |
312 ... return [tree] |
307 ... return [tree] |
313 >>> class aliasrules(basealiasrules): |
308 >>> class aliasrules(basealiasrules): |
314 ... _parsedecl = staticmethod(parse) |
309 ... _parse = staticmethod(parse) |
315 ... _getlist = staticmethod(getlist) |
310 ... _getlist = staticmethod(getlist) |
316 >>> builddecl = aliasrules._builddecl |
311 >>> builddecl = aliasrules._builddecl |
317 >>> builddecl('foo') |
312 >>> builddecl('foo') |
318 ('foo', ('symbol', 'foo'), None, None) |
313 ('foo', ('symbol', 'foo'), None, None) |
319 >>> builddecl('$foo') |
314 >>> builddecl('$foo') |
340 ('foo("bar', None, None, 'at 5: unterminated string') |
335 ('foo("bar', None, None, 'at 5: unterminated string') |
341 >>> builddecl('foo($1, $2, $1)') |
336 >>> builddecl('foo($1, $2, $1)') |
342 ('foo', None, None, 'argument names collide with each other') |
337 ('foo', None, None, 'argument names collide with each other') |
343 """ |
338 """ |
344 try: |
339 try: |
345 tree = cls._parsedecl(decl) |
340 tree = cls._parse(decl) |
346 except error.ParseError as inst: |
341 except error.ParseError as inst: |
347 return (decl, None, None, parseerrordetail(inst)) |
342 return (decl, None, None, parseerrordetail(inst)) |
348 |
343 |
349 if tree[0] == cls._symbolnode: |
344 if tree[0] == cls._symbolnode: |
350 # "name = ...." style |
345 # "name = ...." style |
390 @classmethod |
385 @classmethod |
391 def _builddefn(cls, defn, args): |
386 def _builddefn(cls, defn, args): |
392 """Parse an alias definition into a tree and marks substitutions |
387 """Parse an alias definition into a tree and marks substitutions |
393 |
388 |
394 This function marks alias argument references as ``_aliasarg``. The |
389 This function marks alias argument references as ``_aliasarg``. The |
395 parsing rule is provided by ``_parsedefn()``. |
390 parsing rule is provided by ``_parse()``. |
396 |
391 |
397 ``args`` is a list of alias argument names, or None if the alias |
392 ``args`` is a list of alias argument names, or None if the alias |
398 is declared as a symbol. |
393 is declared as a symbol. |
399 |
394 |
400 >>> parsemap = { |
395 >>> parsemap = { |
402 ... '$1 or $bar': ('or', ('symbol', '$1'), ('symbol', '$bar')), |
397 ... '$1 or $bar': ('or', ('symbol', '$1'), ('symbol', '$bar')), |
403 ... '$10 or baz': ('or', ('symbol', '$10'), ('symbol', 'baz')), |
398 ... '$10 or baz': ('or', ('symbol', '$10'), ('symbol', 'baz')), |
404 ... '"$1" or "foo"': ('or', ('string', '$1'), ('string', 'foo')), |
399 ... '"$1" or "foo"': ('or', ('string', '$1'), ('string', 'foo')), |
405 ... } |
400 ... } |
406 >>> class aliasrules(basealiasrules): |
401 >>> class aliasrules(basealiasrules): |
407 ... _parsedefn = staticmethod(parsemap.__getitem__) |
402 ... _parse = staticmethod(parsemap.__getitem__) |
408 ... _getlist = staticmethod(lambda x: []) |
403 ... _getlist = staticmethod(lambda x: []) |
409 >>> builddefn = aliasrules._builddefn |
404 >>> builddefn = aliasrules._builddefn |
410 >>> def pprint(tree): |
405 >>> def pprint(tree): |
411 ... print prettyformat(tree, ('_aliasarg', 'string', 'symbol')) |
406 ... print prettyformat(tree, ('_aliasarg', 'string', 'symbol')) |
412 >>> args = ['$1', '$2', 'foo'] |
407 >>> args = ['$1', '$2', 'foo'] |