PageRenderTime 82ms CodeModel.GetById 16ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 1ms

/logilab-astng-0.23.1/node_classes.py

#
Python | 903 lines | 587 code | 157 blank | 159 comment | 117 complexity | dcd79e43c4e73e98fe68fc208e9a39d2 MD5 | raw file
  1# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  2# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
  3# copyright 2003-2010 Sylvain Thenault, all rights reserved.
  4# contact mailto:thenault@gmail.com
  5#
  6# This file is part of logilab-astng.
  7#
  8# logilab-astng is free software: you can redistribute it and/or modify it
  9# under the terms of the GNU Lesser General Public License as published by the
 10# Free Software Foundation, either version 2.1 of the License, or (at your
 11# option) any later version.
 12#
 13# logilab-astng is distributed in the hope that it will be useful, but
 14# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 15# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 16# for more details.
 17#
 18# You should have received a copy of the GNU Lesser General Public License along
 19# with logilab-astng. If not, see <http://www.gnu.org/licenses/>.
 20"""Module for some node classes. More nodes in scoped_nodes.py
 21"""
 22
 23import sys
 24
 25from logilab.astng import BUILTINS_MODULE
 26from logilab.astng.exceptions import NoDefault
 27from logilab.astng.bases import (NodeNG, Statement, Instance, InferenceContext,
 28                                 _infer_stmts, YES)
 29from logilab.astng.mixins import BlockRangeMixIn, AssignTypeMixin, \
 30                                 ParentAssignTypeMixin, FromImportMixIn
 31
 32
 33def unpack_infer(stmt, context=None):
 34    """recursively generate nodes inferred by the given statement.
 35    If the inferred value is a list or a tuple, recurse on the elements
 36    """
 37    if isinstance(stmt, (List, Tuple)):
 38        for elt in stmt.elts:
 39            for infered_elt in unpack_infer(elt, context):
 40                yield infered_elt
 41        return
 42    infered = stmt.infer(context).next()
 43    if infered is stmt or infered is YES:
 44        yield infered
 45        return
 46    for infered in stmt.infer(context):
 47        for inf_inf in unpack_infer(infered, context):
 48            yield inf_inf
 49
 50
 51def are_exclusive(stmt1, stmt2, exceptions=None):
 52    """return true if the two given statements are mutually exclusive
 53
 54    `exceptions` may be a list of exception names. If specified, discard If
 55    branches and check one of the statement is in an exception handler catching
 56    one of the given exceptions.
 57
 58    algorithm :
 59     1) index stmt1's parents
 60     2) climb among stmt2's parents until we find a common parent
 61     3) if the common parent is a If or TryExcept statement, look if nodes are
 62        in exclusive branches
 63    """
 64    # index stmt1's parents
 65    stmt1_parents = {}
 66    children = {}
 67    node = stmt1.parent
 68    previous = stmt1
 69    while node:
 70        stmt1_parents[node] = 1
 71        children[node] = previous
 72        previous = node
 73        node = node.parent
 74    # climb among stmt2's parents until we find a common parent
 75    node = stmt2.parent
 76    previous = stmt2
 77    while node:
 78        if node in stmt1_parents:
 79            # if the common parent is a If or TryExcept statement, look if
 80            # nodes are in exclusive branches
 81            if isinstance(node, If) and exceptions is None:
 82                if (node.locate_child(previous)[1]
 83                    is not node.locate_child(children[node])[1]):
 84                    return True
 85            elif isinstance(node, TryExcept):
 86                c2attr, c2node = node.locate_child(previous)
 87                c1attr, c1node = node.locate_child(children[node])
 88                if c1node is not c2node:
 89                    if ((c2attr == 'body' and c1attr == 'handlers' and children[node].catch(exceptions)) or
 90                        (c2attr == 'handlers' and c1attr == 'body' and previous.catch(exceptions)) or
 91                        (c2attr == 'handlers' and c1attr == 'orelse') or
 92                        (c2attr == 'orelse' and c1attr == 'handlers')):
 93                        return True
 94                elif c2attr == 'handlers' and c1attr == 'handlers':
 95                    return previous is not children[node]
 96            return False
 97        previous = node
 98        node = node.parent
 99    return False
100
101
102class LookupMixIn(object):
103    """Mixin looking up a name in the right scope
104    """
105
106    def lookup(self, name):
107        """lookup a variable name
108
109        return the scope node and the list of assignments associated to the given
110        name according to the scope where it has been found (locals, globals or
111        builtin)
112
113        The lookup is starting from self's scope. If self is not a frame itself and
114        the name is found in the inner frame locals, statements will be filtered
115        to remove ignorable statements according to self's location
116        """
117        return self.scope().scope_lookup(self, name)
118
119    def ilookup(self, name):
120        """infered lookup
121
122        return an iterator on infered values of the statements returned by
123        the lookup method
124        """
125        frame, stmts = self.lookup(name)
126        context = InferenceContext()
127        return _infer_stmts(stmts, context, frame)
128
129    def _filter_stmts(self, stmts, frame, offset):
130        """filter statements to remove ignorable statements.
131
132        If self is not a frame itself and the name is found in the inner
133        frame locals, statements will be filtered to remove ignorable
134        statements according to self's location
135        """
136        # if offset == -1, my actual frame is not the inner frame but its parent
137        #
138        # class A(B): pass
139        #
140        # we need this to resolve B correctly
141        if offset == -1:
142            myframe = self.frame().parent.frame()
143        else:
144            myframe = self.frame()
145        if not myframe is frame or self is frame:
146            return stmts
147        mystmt = self.statement()
148        # line filtering if we are in the same frame
149        #
150        # take care node may be missing lineno information (this is the case for
151        # nodes inserted for living objects)
152        if myframe is frame and mystmt.fromlineno is not None:
153            assert mystmt.fromlineno is not None, mystmt
154            mylineno = mystmt.fromlineno + offset
155        else:
156            # disabling lineno filtering
157            mylineno = 0
158        _stmts = []
159        _stmt_parents = []
160        for node in stmts:
161            stmt = node.statement()
162            # line filtering is on and we have reached our location, break
163            if mylineno > 0 and stmt.fromlineno > mylineno:
164                break
165            assert hasattr(node, 'ass_type'), (node, node.scope(),
166                                               node.scope().locals)
167            ass_type = node.ass_type()
168
169            if node.has_base(self):
170                break
171
172            _stmts, done = ass_type._get_filtered_stmts(self, node, _stmts, mystmt)
173            if done:
174                break
175
176            optional_assign = ass_type.optional_assign
177            if optional_assign and ass_type.parent_of(self):
178                # we are inside a loop, loop var assigment is hidding previous
179                # assigment
180                _stmts = [node]
181                _stmt_parents = [stmt.parent]
182                continue
183
184            # XXX comment various branches below!!!
185            try:
186                pindex = _stmt_parents.index(stmt.parent)
187            except ValueError:
188                pass
189            else:
190                # we got a parent index, this means the currently visited node
191                # is at the same block level as a previously visited node
192                if _stmts[pindex].ass_type().parent_of(ass_type):
193                    # both statements are not at the same block level
194                    continue
195                # if currently visited node is following previously considered
196                # assignement and both are not exclusive, we can drop the
197                # previous one. For instance in the following code ::
198                #
199                #   if a:
200                #     x = 1
201                #   else:
202                #     x = 2
203                #   print x
204                #
205                # we can't remove neither x = 1 nor x = 2 when looking for 'x'
206                # of 'print x'; while in the following ::
207                #
208                #   x = 1
209                #   x = 2
210                #   print x
211                #
212                # we can remove x = 1 when we see x = 2
213                #
214                # moreover, on loop assignment types, assignment won't
215                # necessarily be done if the loop has no iteration, so we don't
216                # want to clear previous assigments if any (hence the test on
217                # optional_assign)
218                if not (optional_assign or are_exclusive(_stmts[pindex], node)):
219                    del _stmt_parents[pindex]
220                    del _stmts[pindex]
221            if isinstance(node, AssName):
222                if not optional_assign and stmt.parent is mystmt.parent:
223                    _stmts = []
224                    _stmt_parents = []
225            elif isinstance(node, DelName):
226                _stmts = []
227                _stmt_parents = []
228                continue
229            if not are_exclusive(self, node):
230                _stmts.append(node)
231                _stmt_parents.append(stmt.parent)
232        return _stmts
233
234# Name classes
235
236class AssName(LookupMixIn, ParentAssignTypeMixin, NodeNG):
237    """class representing an AssName node"""
238
239
240class DelName(LookupMixIn, ParentAssignTypeMixin, NodeNG):
241    """class representing a DelName node"""
242
243
244class Name(LookupMixIn, NodeNG):
245    """class representing a Name node"""
246
247
248
249
250#####################   node classes   ########################################
251
252class Arguments(NodeNG, AssignTypeMixin):
253    """class representing an Arguments node"""
254    _astng_fields = ('args', 'defaults')
255    args = None
256    defaults = None
257
258    def __init__(self, vararg=None, kwarg=None):
259        self.vararg = vararg
260        self.kwarg = kwarg
261
262    def _infer_name(self, frame, name):
263        if self.parent is frame:
264            return name
265        return None
266
267    def format_args(self):
268        """return arguments formatted as string"""
269        result = [_format_args(self.args, self.defaults)]
270        if self.vararg:
271            result.append('*%s' % self.vararg)
272        if self.kwarg:
273            result.append('**%s' % self.kwarg)
274        return ', '.join(result)
275
276    def default_value(self, argname):
277        """return the default value for an argument
278
279        :raise `NoDefault`: if there is no default value defined
280        """
281        i = _find_arg(argname, self.args)[0]
282        if i is not None:
283            idx = i - (len(self.args) - len(self.defaults))
284            if idx >= 0:
285                return self.defaults[idx]
286        raise NoDefault()
287
288    def is_argument(self, name):
289        """return True if the name is defined in arguments"""
290        if name == self.vararg:
291            return True
292        if name == self.kwarg:
293            return True
294        return self.find_argname(name, True)[1] is not None
295
296    def find_argname(self, argname, rec=False):
297        """return index and Name node with given name"""
298        if self.args: # self.args may be None in some cases (builtin function)
299            return _find_arg(argname, self.args, rec)
300        return None, None
301
302
303def _find_arg(argname, args, rec=False):
304    for i, arg in enumerate(args):
305        if isinstance(arg, Tuple):
306            if rec:
307                found = _find_arg(argname, arg.elts)
308                if found[0] is not None:
309                    return found
310        elif arg.name == argname:
311            return i, arg
312    return None, None
313
314
315def _format_args(args, defaults=None):
316    values = []
317    if args is None:
318        return ''
319    if defaults is not None:
320        default_offset = len(args) - len(defaults)
321    for i, arg in enumerate(args):
322        if isinstance(arg, Tuple):
323            values.append('(%s)' % _format_args(arg.elts))
324        else:
325            values.append(arg.name)
326            if defaults is not None and i >= default_offset:
327                values[-1] += '=' + defaults[i-default_offset].as_string()
328    return ', '.join(values)
329
330
331class AssAttr(NodeNG, ParentAssignTypeMixin):
332    """class representing an AssAttr node"""
333    _astng_fields = ('expr',)
334    expr = None
335
336class Assert(Statement):
337    """class representing an Assert node"""
338    _astng_fields = ('test', 'fail',)
339    test = None
340    fail = None
341
342class Assign(Statement, AssignTypeMixin):
343    """class representing an Assign node"""
344    _astng_fields = ('targets', 'value',)
345    targets = None
346    value = None
347
348class AugAssign(Statement, AssignTypeMixin):
349    """class representing an AugAssign node"""
350    _astng_fields = ('target', 'value',)
351    target = None
352    value = None
353
354class Backquote(NodeNG):
355    """class representing a Backquote node"""
356    _astng_fields = ('value',)
357    value = None
358
359class BinOp(NodeNG):
360    """class representing a BinOp node"""
361    _astng_fields = ('left', 'right',)
362    left = None
363    right = None
364
365class BoolOp(NodeNG):
366    """class representing a BoolOp node"""
367    _astng_fields = ('values',)
368    values = None
369
370class Break(Statement):
371    """class representing a Break node"""
372
373
374class CallFunc(NodeNG):
375    """class representing a CallFunc node"""
376    _astng_fields = ('func', 'args', 'starargs', 'kwargs')
377    func = None
378    args = None
379    starargs = None
380    kwargs = None
381
382    def __init__(self):
383        self.starargs = None
384        self.kwargs = None
385
386class Compare(NodeNG):
387    """class representing a Compare node"""
388    _astng_fields = ('left', 'ops',)
389    left = None
390    ops = None
391
392    def get_children(self):
393        """override get_children for tuple fields"""
394        yield self.left
395        for _, comparator in self.ops:
396            yield comparator # we don't want the 'op'
397
398    def last_child(self):
399        """override last_child"""
400        # XXX maybe if self.ops:
401        return self.ops[-1][1]
402        #return self.left
403
404class Comprehension(NodeNG):
405    """class representing a Comprehension node"""
406    _astng_fields = ('target', 'iter' ,'ifs')
407    target = None
408    iter = None
409    ifs = None
410
411    optional_assign = True
412    def ass_type(self):
413        return self
414
415    def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt):
416        """method used in filter_stmts"""
417        if self is mystmt:
418            if isinstance(lookup_node, (Const, Name)):
419                return [lookup_node], True
420
421        elif self.statement() is mystmt:
422            # original node's statement is the assignment, only keeps
423            # current node (gen exp, list comp)
424
425            return [node], True
426
427        return stmts, False
428
429
430class Const(NodeNG, Instance):
431    """represent a constant node like num, str, bool, None, bytes"""
432
433    def __init__(self, value=None):
434        self.value = value
435
436    def getitem(self, index, context=None):
437        if isinstance(self.value, basestring):
438            return Const(self.value[index])
439        raise TypeError('%r (value=%s)' % (self, self.value))
440
441    def has_dynamic_getattr(self):
442        return False
443
444    def itered(self):
445        if isinstance(self.value, basestring):
446            return self.value
447        raise TypeError()
448
449    def pytype(self):
450        return self._proxied.qname()
451
452
453class Continue(Statement):
454    """class representing a Continue node"""
455
456
457class Decorators(NodeNG):
458    """class representing a Decorators node"""
459    _astng_fields = ('nodes',)
460    nodes = None
461
462    def __init__(self, nodes=None):
463        self.nodes = nodes
464
465    def scope(self):
466        # skip the function node to go directly to the upper level scope
467        return self.parent.parent.scope()
468
469class DelAttr(NodeNG, ParentAssignTypeMixin):
470    """class representing a DelAttr node"""
471    _astng_fields = ('expr',)
472    expr = None
473
474
475class Delete(Statement, AssignTypeMixin):
476    """class representing a Delete node"""
477    _astng_fields = ('targets',)
478    targets = None
479
480
481class Dict(NodeNG, Instance):
482    """class representing a Dict node"""
483    _astng_fields = ('items',)
484
485    def __init__(self, items=None):
486        if items is None:
487            self.items = []
488        else:
489            self.items = [(const_factory(k), const_factory(v))
490                          for k,v in items.iteritems()]
491
492    def pytype(self):
493        return '%s.dict' % BUILTINS_MODULE
494
495    def get_children(self):
496        """get children of a Dict node"""
497        # overrides get_children
498        for key, value in self.items:
499            yield key
500            yield value
501
502    def last_child(self):
503        """override last_child"""
504        if self.items:
505            return self.items[-1][1]
506        return None
507
508    def itered(self):
509        return self.items[::2]
510
511    def getitem(self, key, context=None):
512        for i in xrange(0, len(self.items), 2):
513            for inferedkey in self.items[i].infer(context):
514                if inferedkey is YES:
515                    continue
516                if isinstance(inferedkey, Const) and inferedkey.value == key:
517                    return self.items[i+1]
518        raise IndexError(key)
519
520
521class Discard(Statement):
522    """class representing a Discard node"""
523    _astng_fields = ('value',)
524    value = None
525
526
527class Ellipsis(NodeNG):
528    """class representing an Ellipsis node"""
529
530
531class EmptyNode(NodeNG):
532    """class representing an EmptyNode node"""
533
534
535class ExceptHandler(Statement, AssignTypeMixin):
536    """class representing an ExceptHandler node"""
537    _astng_fields = ('type', 'name', 'body',)
538    type = None
539    name = None
540    body = None
541
542    def _blockstart_toline(self):
543        if self.name:
544            return self.name.tolineno
545        elif self.type:
546            return self.type.tolineno
547        else:
548            return self.lineno
549
550    def set_line_info(self, lastchild):
551        self.fromlineno = self.lineno
552        self.tolineno = lastchild.tolineno
553        self.blockstart_tolineno = self._blockstart_toline()
554
555    def catch(self, exceptions):
556        if self.type is None or exceptions is None:
557            return True
558        for node in self.type.nodes_of_class(Name):
559            if node.name in exceptions:
560                return True
561
562
563class Exec(Statement):
564    """class representing an Exec node"""
565    _astng_fields = ('expr', 'globals', 'locals',)
566    expr = None
567    globals = None
568    locals = None
569
570
571class ExtSlice(NodeNG):
572    """class representing an ExtSlice node"""
573    _astng_fields = ('dims',)
574    dims = None
575
576class For(BlockRangeMixIn, AssignTypeMixin, Statement):
577    """class representing a For node"""
578    _astng_fields = ('target', 'iter', 'body', 'orelse',)
579    target = None
580    iter = None
581    body = None
582    orelse = None
583
584    optional_assign = True
585    def _blockstart_toline(self):
586        return self.iter.tolineno
587
588
589class From(FromImportMixIn, Statement):
590    """class representing a From node"""
591
592    def __init__(self,  fromname, names, level=0):
593        self.modname = fromname
594        self.names = names
595        self.level = level
596
597class Getattr(NodeNG):
598    """class representing a Getattr node"""
599    _astng_fields = ('expr',)
600    expr = None
601
602
603class Global(Statement):
604    """class representing a Global node"""
605
606    def __init__(self, names):
607        self.names = names
608
609    def _infer_name(self, frame, name):
610        return name
611
612
613class If(BlockRangeMixIn, Statement):
614    """class representing an If node"""
615    _astng_fields = ('test', 'body', 'orelse')
616    test = None
617    body = None
618    orelse = None
619
620    def _blockstart_toline(self):
621        return self.test.tolineno
622
623    def block_range(self, lineno):
624        """handle block line numbers range for if statements"""
625        if lineno == self.body[0].fromlineno:
626            return lineno, lineno
627        if lineno <= self.body[-1].tolineno:
628            return lineno, self.body[-1].tolineno
629        return self._elsed_block_range(lineno, self.orelse,
630                                       self.body[0].fromlineno - 1)
631
632
633class IfExp(NodeNG):
634    """class representing an IfExp node"""
635    _astng_fields = ('test', 'body', 'orelse')
636    test = None
637    body = None
638    orelse = None
639
640
641class Import(FromImportMixIn, Statement):
642    """class representing an Import node"""
643
644
645class Index(NodeNG):
646    """class representing an Index node"""
647    _astng_fields = ('value',)
648    value = None
649
650
651class Keyword(NodeNG):
652    """class representing a Keyword node"""
653    _astng_fields = ('value',)
654    value = None
655
656
657class List(NodeNG, Instance, ParentAssignTypeMixin):
658    """class representing a List node"""
659    _astng_fields = ('elts',)
660
661    def __init__(self, elts=None):
662        if elts is None:
663            self.elts = []
664        else:
665            self.elts = [const_factory(e) for e in elts]
666
667    def pytype(self):
668        return '%s.list' % BUILTINS_MODULE
669
670    def getitem(self, index, context=None):
671        return self.elts[index]
672
673    def itered(self):
674        return self.elts
675
676
677class Nonlocal(Statement):
678    """class representing a Nonlocal node"""
679
680    def __init__(self, names):
681        self.names = names
682
683    def _infer_name(self, frame, name):
684        return name
685
686
687class Pass(Statement):
688    """class representing a Pass node"""
689
690
691class Print(Statement):
692    """class representing a Print node"""
693    _astng_fields = ('dest', 'values',)
694    dest = None
695    values = None
696
697
698class Raise(Statement):
699    """class representing a Raise node"""
700    exc = None
701    if sys.version_info < (3, 0):
702        _astng_fields = ('exc', 'inst', 'tback')
703        inst = None
704        tback = None
705    else:
706        _astng_fields = ('exc', 'cause')
707        exc = None
708        cause = None
709
710    def raises_not_implemented(self):
711        if not self.exc:
712            return
713        for name in self.exc.nodes_of_class(Name):
714            if name.name == 'NotImplementedError':
715                return True
716
717
718class Return(Statement):
719    """class representing a Return node"""
720    _astng_fields = ('value',)
721    value = None
722
723
724class Set(NodeNG, Instance, ParentAssignTypeMixin):
725    """class representing a Set node"""
726    _astng_fields = ('elts',)
727
728    def __init__(self, elts=None):
729        if elts is None:
730            self.elts = []
731        else:
732            self.elts = [const_factory(e) for e in elts]
733
734    def pytype(self):
735        return '%s.set' % BUILTINS_MODULE
736
737    def itered(self):
738        return self.elts
739
740
741class Slice(NodeNG):
742    """class representing a Slice node"""
743    _astng_fields = ('lower', 'upper', 'step')
744    lower = None
745    upper = None
746    step = None
747
748class Starred(NodeNG):
749    """class representing a Starred node"""
750    _astng_fields = ('value',)
751    value = None
752
753
754class Subscript(NodeNG):
755    """class representing a Subscript node"""
756    _astng_fields = ('value', 'slice')
757    value = None
758    slice = None
759
760
761class TryExcept(BlockRangeMixIn, Statement):
762    """class representing a TryExcept node"""
763    _astng_fields = ('body', 'handlers', 'orelse',)
764    body = None
765    handlers = None
766    orelse = None
767
768    def _infer_name(self, frame, name):
769        return name
770
771    def _blockstart_toline(self):
772        return self.lineno
773
774    def block_range(self, lineno):
775        """handle block line numbers range for try/except statements"""
776        last = None
777        for exhandler in self.handlers:
778            if exhandler.type and lineno == exhandler.type.fromlineno:
779                return lineno, lineno
780            if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
781                return lineno, exhandler.body[-1].tolineno
782            if last is None:
783                last = exhandler.body[0].fromlineno - 1
784        return self._elsed_block_range(lineno, self.orelse, last)
785
786
787class TryFinally(BlockRangeMixIn, Statement):
788    """class representing a TryFinally node"""
789    _astng_fields = ('body', 'finalbody',)
790    body = None
791    finalbody = None
792
793    def _blockstart_toline(self):
794        return self.lineno
795
796    def block_range(self, lineno):
797        """handle block line numbers range for try/finally statements"""
798        child = self.body[0]
799        # py2.5 try: except: finally:
800        if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno
801            and lineno > self.fromlineno and lineno <= child.tolineno):
802            return child.block_range(lineno)
803        return self._elsed_block_range(lineno, self.finalbody)
804
805
806class Tuple(NodeNG, Instance, ParentAssignTypeMixin):
807    """class representing a Tuple node"""
808    _astng_fields = ('elts',)
809
810    def __init__(self, elts=None):
811        if elts is None:
812            self.elts = []
813        else:
814            self.elts = [const_factory(e) for e in elts]
815
816    def pytype(self):
817        return '%s.tuple' % BUILTINS_MODULE
818
819    def getitem(self, index, context=None):
820        return self.elts[index]
821
822    def itered(self):
823        return self.elts
824
825
826class UnaryOp(NodeNG):
827    """class representing an UnaryOp node"""
828    _astng_fields = ('operand',)
829    operand = None
830
831
832class While(BlockRangeMixIn, Statement):
833    """class representing a While node"""
834    _astng_fields = ('test', 'body', 'orelse',)
835    test = None
836    body = None
837    orelse = None
838
839    def _blockstart_toline(self):
840        return self.test.tolineno
841
842    def block_range(self, lineno):
843        """handle block line numbers range for for and while statements"""
844        return self. _elsed_block_range(lineno, self.orelse)
845
846
847class With(BlockRangeMixIn, AssignTypeMixin, Statement):
848    """class representing a With node"""
849    _astng_fields = ('expr', 'vars', 'body')
850    expr = None
851    vars = None
852    body = None
853
854    def _blockstart_toline(self):
855        if self.vars:
856            return self.vars.tolineno
857        else:
858            return self.expr.tolineno
859
860
861class Yield(NodeNG):
862    """class representing a Yield node"""
863    _astng_fields = ('value',)
864    value = None
865
866# constants ##############################################################
867
868CONST_CLS = {
869    list: List,
870    tuple: Tuple,
871    dict: Dict,
872    set: Set,
873    type(None): Const,
874    }
875
876def _update_const_classes():
877    """update constant classes, so the keys of CONST_CLS can be reused"""
878    klasses = (bool, int, float, complex, str)
879    if sys.version_info < (3, 0):
880        klasses += (unicode, long)
881    if sys.version_info >= (2, 6):
882        klasses += (bytes,)
883    for kls in klasses:
884        CONST_CLS[kls] = Const
885_update_const_classes()
886
887def const_factory(value):
888    """return an astng node for a python value"""
889    # since const_factory is called to evaluate content of container (eg list,
890    # tuple), it may be called with some node as argument that should be left
891    # untouched
892    if isinstance(value, NodeNG):
893        return value
894    try:
895        return CONST_CLS[value.__class__](value)
896    except (KeyError, AttributeError):
897        # some constants (like from gtk._gtk) don't have their class in
898        # CONST_CLS, though we can "assert isinstance(value, tuple(CONST_CLS))"
899        if isinstance(value, tuple(CONST_CLS)):
900            return Const(value)
901        node = EmptyNode()
902        node.object = value
903        return node