summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node_classes.py79
-rw-r--r--protocols.py32
-rw-r--r--scoped_nodes.py27
3 files changed, 76 insertions, 62 deletions
diff --git a/node_classes.py b/node_classes.py
index 5250f975..98b4ea76 100644
--- a/node_classes.py
+++ b/node_classes.py
@@ -75,9 +75,45 @@ def are_exclusive(stmt1, stmt2, exceptions=None):
node = node.parent
return False
+class FilterStmtsMixin(object):
+ """Mixin for statement filtering and assignment type"""
+ def _get_filtered_stmts(self, _, node, _stmts, mystmt):
+ """method used in _filter_stmts to get statemtents and trigger break"""
+ if self.statement() is mystmt:
+ # original node's statement is the assignment, only keep
+ # current node (gen exp, list comp)
+ return [node], True
+ return _stmts, False
-class Arguments(NodeNG):
+ def ass_type(self):
+ return self
+
+
+class AssignTypeMixin(object):
+
+ def ass_type(self):
+ return self
+
+ def _get_filtered_stmts(self, lookup_node, node, _stmts, mystmt):
+ """method used in filter_stmts"""
+ if self is mystmt:
+ return _stmts, True
+ if self.statement() is mystmt:
+ # original node's statement is the assignment, only keep
+ # current node (gen exp, list comp)
+ return [node], True
+ return _stmts, False
+
+
+class ParentAssignTypeMixin(AssignTypeMixin):
+
+ def ass_type(self):
+ return self.parent.ass_type()
+
+
+
+class Arguments(NodeNG, AssignTypeMixin):
"""class representing an Arguments node"""
def __init__(self, vararg=None, kwarg=None):
self.vararg = vararg
@@ -152,7 +188,7 @@ def _format_args(args, defaults=None):
return ', '.join(values)
-class AssAttr(NodeNG):
+class AssAttr(NodeNG, ParentAssignTypeMixin):
"""class representing an AssAttr node"""
@@ -160,11 +196,11 @@ class Assert(StmtMixIn, NodeNG):
"""class representing an Assert node"""
-class Assign(StmtMixIn, NodeNG):
+class Assign(StmtMixIn, NodeNG, AssignTypeMixin):
"""class representing an Assign node"""
-class AugAssign(StmtMixIn, NodeNG):
+class AugAssign(StmtMixIn, NodeNG, AssignTypeMixin):
"""class representing an AugAssign node"""
@@ -209,6 +245,24 @@ class Compare(NodeNG):
class Comprehension(NodeNG):
"""class representing a Comprehension node"""
+ def ass_type(self):
+ return self
+
+ def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt):
+ """method used in filter_stmts"""
+ if self is mystmt:
+ from logilab.astng.nodes import Name # XXX remove me
+ if isinstance(lookup_node, (Const, Name)):
+ return [lookup_node], True
+
+ elif self.statement() is mystmt:
+ # original node's statement is the assignment, only keeps
+ # current node (gen exp, list comp)
+
+ return [node], True
+
+ return stmts, False
+
class Const(NodeNG, Instance):
"""represent a Str or Num node"""
@@ -241,11 +295,11 @@ class Decorators(NodeNG):
# skip the function node to go directly to the upper level scope
return self.parent.parent.scope()
-class DelAttr(NodeNG):
+class DelAttr(NodeNG, ParentAssignTypeMixin):
"""class representing a DelAttr node"""
-class Delete(StmtMixIn, NodeNG):
+class Delete(StmtMixIn, NodeNG, AssignTypeMixin):
"""class representing a Delete node"""
@@ -293,7 +347,7 @@ class EmptyNode(NodeNG):
"""class representing an EmptyNode node"""
-class ExceptHandler(StmtMixIn, NodeNG):
+class ExceptHandler(StmtMixIn, NodeNG, AssignTypeMixin):
"""class representing an ExceptHandler node"""
def __init__(self):
@@ -340,14 +394,14 @@ class ExtSlice(NodeNG):
"""class representing an ExtSlice node"""
-class For(BlockRangeMixIn, StmtMixIn, NodeNG):
+class For(BlockRangeMixIn, StmtMixIn, AssignTypeMixin, NodeNG):
"""class representing a For node"""
def _blockstart_toline(self):
return self.iter.tolineno
-class FromImportMixIn(BaseClass):
+class FromImportMixIn(BaseClass, FilterStmtsMixin):
"""MixIn for From and Import Nodes"""
def _infer_name(self, frame, name):
@@ -437,7 +491,7 @@ class Keyword(NodeNG):
"""class representing a Keyword node"""
-class List(NodeNG, Instance):
+class List(NodeNG, Instance, ParentAssignTypeMixin):
"""class representing a List node"""
def pytype(self):
@@ -450,6 +504,7 @@ class List(NodeNG, Instance):
return self.elts
+
class ListComp(NodeNG):
"""class representing a ListComp node"""
@@ -515,7 +570,7 @@ class TryFinally(BlockRangeMixIn, StmtMixIn, NodeNG):
return self._elsed_block_range(lineno, self.finalbody)
-class Tuple(NodeNG, Instance):
+class Tuple(NodeNG, Instance, ParentAssignTypeMixin):
"""class representing a Tuple node"""
def pytype(self):
@@ -542,7 +597,7 @@ class While(BlockRangeMixIn, StmtMixIn, NodeNG):
"""handle block line numbers range for for and while statements"""
return self. _elsed_block_range(lineno, self.orelse)
-class With(BlockRangeMixIn, StmtMixIn, NodeNG):
+class With(BlockRangeMixIn, StmtMixIn, AssignTypeMixin, NodeNG):
"""class representing a With node"""
def _blockstart_toline(self):
diff --git a/protocols.py b/protocols.py
index 9b5c744b..40de339c 100644
--- a/protocols.py
+++ b/protocols.py
@@ -303,35 +303,3 @@ def with_assigned_stmts(self, node, context=None, asspath=None):
nodes.With.assigned_stmts = raise_if_nothing_infered(with_assigned_stmts)
-def parent_ass_type(self, context=None):
- return self.parent.ass_type()
-
-nodes.Tuple.ass_type = parent_ass_type
-nodes.List.ass_type = parent_ass_type
-nodes.AssName.ass_type = parent_ass_type
-nodes.AssAttr.ass_type = parent_ass_type
-nodes.DelName.ass_type = parent_ass_type
-nodes.DelAttr.ass_type = parent_ass_type
-
-def end_ass_type(self):
- return self
-
-# XXX if you add ass_type to a class, you should probably modify
-# lookup.LookupMixIn.filter_stmts around line ::
-#
-# if ass_type is mystmt and not isinstance(ass_type, (nodes.Class, ...)):
-nodes.Arguments.ass_type = end_ass_type
-nodes.Assign.ass_type = end_ass_type
-nodes.AugAssign.ass_type = end_ass_type
-nodes.Class.ass_type = end_ass_type
-nodes.Comprehension.ass_type = end_ass_type
-nodes.Delete.ass_type = end_ass_type
-nodes.ExceptHandler.ass_type = end_ass_type
-nodes.For.ass_type = end_ass_type
-nodes.From.ass_type = end_ass_type
-nodes.Function.ass_type = end_ass_type
-nodes.Import.ass_type = end_ass_type
-nodes.With.ass_type = end_ass_type
-
-
-
diff --git a/scoped_nodes.py b/scoped_nodes.py
index a40de8cb..c6851bad 100644
--- a/scoped_nodes.py
+++ b/scoped_nodes.py
@@ -38,7 +38,8 @@ from logilab.astng import MANAGER, NotFoundError, NoDefault, \
ASTNGBuildingException, InferenceError
from logilab.astng.node_classes import (Const, Comprehension, Dict,
From, For, Import, List, Pass, Raise, Return, Tuple, Yield, DelAttr,
- are_exclusive, const_factory as cf, unpack_infer)
+ are_exclusive, const_factory as cf, unpack_infer, FilterStmtsMixin,
+ ParentAssignTypeMixin)
from logilab.astng.bases import (NodeNG, StmtMixIn, BaseClass, YES,
InferenceContext, Instance, Generator,
UnboundMethod, BoundMethod, _infer_stmts, copy_context)
@@ -152,20 +153,10 @@ class LookupMixIn(BaseClass):
if node.has_base(self):
break
- if ass_type is mystmt and not isinstance(ass_type, (Class,
- Function, Import, From, Lambda)):
- if not isinstance(ass_type, Comprehension):
- break
- if isinstance(self, (Const, Name)):
- _stmts = [self]
- break
- elif ass_type.statement() is mystmt:
- # original node's statement is the assignment, only keeps
- # current node (gen exp, list comp)
- _stmts = [node]
+ _stmts, done = ass_type._get_filtered_stmts(self, node, _stmts, mystmt)
+ if done:
break
-
optional_assign = isinstance(ass_type, (For, Comprehension))
if optional_assign and ass_type.parent_of(self):
# we are inside a loop, loop var assigment is hidding previous
@@ -361,11 +352,11 @@ class LocalsDictNodeNG(LookupMixIn, NodeNG):
# Name classses
-class AssName(LookupMixIn, NodeNG):
+class AssName(LookupMixIn, ParentAssignTypeMixin, NodeNG):
"""class representing an AssName node"""
-class DelName(LookupMixIn, NodeNG):
+class DelName(LookupMixIn, ParentAssignTypeMixin, NodeNG):
"""class representing a DelName node"""
@@ -572,7 +563,8 @@ GenExpr.scope_lookup = LocalsDictNodeNG._scope_lookup
# Function ###################################################################
-class Lambda(LocalsDictNodeNG):
+
+class Lambda(LocalsDictNodeNG, FilterStmtsMixin):
# function's type, 'function' | 'method' | 'staticmethod' | 'classmethod'
type = 'function'
@@ -620,7 +612,6 @@ class Lambda(LocalsDictNodeNG):
frame = self
return frame._scope_lookup(node, name, offset)
-
class Function(StmtMixIn, Lambda):
def __init__(self):
@@ -782,7 +773,7 @@ def _iface_hdlr(iface_node):
return True
-class Class(StmtMixIn, LocalsDictNodeNG):
+class Class(StmtMixIn, LocalsDictNodeNG, FilterStmtsMixin):
# some of the attributes below are set by the builder module or
# by a raw factories