PageRenderTime 58ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/logilab-astng-0.23.1/node_classes.py

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