Example #1
0
    def eval_statement(self, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `pr.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        types = self.eval_element(stmt.get_rhs())

        if seek_name:
            types = finder.check_tuple_assignments(types, seek_name)

        first_operation = stmt.first_operation()
        if first_operation not in ('=', None) and not isinstance(stmt, er.InstanceElement):  # TODO don't check for this.
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            parent = er.wrap(self, stmt.get_parent_scope())
            left = self.find_types(parent, name, stmt.start_pos, search_global=True)
            if isinstance(stmt.get_parent_until(pr.ForStmt), pr.ForStmt):
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable.
                for r in types:
                    left = precedence.calculate(self, left, operator, [r])
                types = left
            else:
                types = precedence.calculate(self, left, operator, types)
        debug.dbg('eval_statement result %s', types)
        return types
    def eval_statement(self, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `pr.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        types = self.eval_element(stmt.get_rhs())

        if seek_name:
            types = finder.check_tuple_assignments(types, seek_name)

        first_operation = stmt.first_operation()
        if first_operation not in ('=', None) and not isinstance(stmt, er.InstanceElement):  # TODO don't check for this.
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            parent = er.wrap(self, stmt.get_parent_scope())
            left = self.find_types(parent, name, stmt.start_pos, search_global=True)
            if isinstance(stmt.get_parent_until(pr.ForStmt), pr.ForStmt):
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable.
                for r in types:
                    left = precedence.calculate(self, left, operator, [r])
                types = left
            else:
                types = precedence.calculate(self, left, operator, types)
        debug.dbg('eval_statement result %s', types)
        return types
Example #3
0
    def eval_statement(self, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `tree.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        rhs = stmt.get_rhs()
        types = self.eval_element(rhs)

        if seek_name:
            types = finder.check_tuple_assignments(self, types, seek_name)

        first_operation = stmt.first_operation()
        if first_operation not in ('=', None) and not isinstance(
                stmt, er.InstanceElement
        ) and first_operation.type == 'operator':  # TODO don't check for this. id:458 gh:459
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            parent = self.wrap(stmt.get_parent_scope())
            left = self.find_types(parent,
                                   name,
                                   stmt.start_pos,
                                   search_global=True)

            for_stmt = stmt.get_parent_until(tree.ForStmt)
            if isinstance(for_stmt, tree.ForStmt) and types \
                    and for_stmt.defines_one_name():
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable. Also only do it, if the variable is not a tuple.
                node = for_stmt.get_input_node()
                for_iterables = self.eval_element(node)
                ordered = list(iterable.py__iter__(self, for_iterables, node))

                for index_types in ordered:
                    dct = {str(for_stmt.children[1]): index_types}
                    self.predefined_if_name_dict_dict[for_stmt] = dct
                    t = self.eval_element(rhs)
                    left = precedence.calculate(self, left, operator, t)
                types = left
                if ordered:
                    # If there are no for entries, we cannot iterate and the
                    # types are defined by += entries. Therefore the for loop
                    # is never called.
                    del self.predefined_if_name_dict_dict[for_stmt]
            else:
                types = precedence.calculate(self, left, operator, types)
        debug.dbg('eval_statement result %s', types)
        return types
Example #4
0
    def eval_statement(self, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `tree.ExprStmt`.
        """
        debug.dbg("eval_statement %s (%s)", stmt, seek_name)
        rhs = stmt.get_rhs()
        types = self.eval_element(rhs)

        if seek_name:
            types = finder.check_tuple_assignments(self, types, seek_name)

        first_operation = stmt.first_operation()
        if first_operation not in ("=", None) and not isinstance(
            stmt, er.InstanceElement
        ):  # TODO don't check for this.
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            parent = self.wrap(stmt.get_parent_scope())
            left = self.find_types(parent, name, stmt.start_pos, search_global=True)

            for_stmt = stmt.get_parent_until(tree.ForStmt)
            if isinstance(for_stmt, tree.ForStmt) and types and for_stmt.defines_one_name():
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable. Also only do it, if the variable is not a tuple.
                node = for_stmt.get_input_node()
                for_iterables = self.eval_element(node)
                ordered = list(iterable.py__iter__(self, for_iterables, node))

                for index_types in ordered:
                    dct = {str(for_stmt.children[1]): index_types}
                    self.predefined_if_name_dict_dict[for_stmt] = dct
                    t = self.eval_element(rhs)
                    left = precedence.calculate(self, left, operator, t)
                types = left
                if ordered:
                    # If there are no for entries, we cannot iterate and the
                    # types are defined by += entries. Therefore the for loop
                    # is never called.
                    del self.predefined_if_name_dict_dict[for_stmt]
            else:
                types = precedence.calculate(self, left, operator, types)
        debug.dbg("eval_statement result %s", types)
        return types
Example #5
0
    def _eval_stmt(self, context, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `tree.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        rhs = stmt.get_rhs()
        types = self.eval_element(context, rhs)

        if seek_name:
            c_node = ContextualizedName(context, seek_name)
            types = finder.check_tuple_assignments(self, c_node, types)

        first_operation = stmt.first_operation()
        if first_operation not in (
                '=', None) and first_operation.type == 'operator':
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            left = context.py__getattribute__(name,
                                              position=stmt.start_pos,
                                              search_global=True)

            for_stmt = tree.search_ancestor(stmt, 'for_stmt')
            if for_stmt is not None and for_stmt.type == 'for_stmt' and types \
                    and for_stmt.defines_one_name():
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable. Also only do it, if the variable is not a tuple.
                node = for_stmt.get_input_node()
                cn = ContextualizedNode(context, node)
                ordered = list(iterable.py__iter__(self, cn.infer(), cn))

                for lazy_context in ordered:
                    dct = {str(for_stmt.children[1]): lazy_context.infer()}
                    with helpers.predefine_names(context, for_stmt, dct):
                        t = self.eval_element(context, rhs)
                        left = precedence.calculate(self, context, left,
                                                    operator, t)
                types = left
            else:
                types = precedence.calculate(self, context, left, operator,
                                             types)
        debug.dbg('eval_statement result %s', types)
        return types
Example #6
0
    def calculate_children(evaluator, children):
        """
        Calculate a list of children with operators.
        """
        iterator = iter(children)
        types = evaluator.eval_element(next(iterator))
        for operator in iterator:
            try:# PATCH: Catches StopIteration error
                right = next(iterator)
                if tree.is_node(operator, 'comp_op'):  # not in / is not
                    operator = ' '.join(str(c.value) for c in operator.children)

                # handle lazy evaluation of and/or here.
                if operator in ('and', 'or'):
                    left_bools = set([left.py__bool__() for left in types])
                    if left_bools == set([True]):
                        if operator == 'and':
                            types = evaluator.eval_element(right)
                    elif left_bools == set([False]):
                        if operator != 'and':
                            types = evaluator.eval_element(right)
                    # Otherwise continue, because of uncertainty.
                else:
                    types = calculate(evaluator, types, operator,
                                      evaluator.eval_element(right))
            except StopIteration:
                debug.warning('calculate_children StopIteration %s', types)
        debug.dbg('calculate_children types %s', types)
        return types
Example #7
0
 def _eval_element_not_cached(self, element):
     debug.dbg('eval_element %s@%s', element, element.start_pos)
     types = set()
     if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node(
             element, 'atom'):
         types = self._eval_atom(element)
     elif isinstance(element, tree.Keyword):
         # For False/True/None
         if element.value in ('False', 'True', 'None'):
             types.add(compiled.builtin_from_name(self, element.value))
         # else: print e.g. could be evaluated like this in Python 2.7
     elif element.isinstance(tree.Lambda):
         types = set([er.LambdaWrapper(self, element)])
     elif element.isinstance(er.LambdaWrapper):
         types = set([element
                      ])  # TODO this is no real evaluation. id:121 gh:122
     elif element.type == 'expr_stmt':
         types = self.eval_statement(element)
     elif element.type in ('power', 'atom_expr'):
         types = self._eval_atom(element.children[0])
         for trailer in element.children[1:]:
             if trailer == '**':  # has a power operation.
                 right = self.eval_element(element.children[2])
                 types = set(
                     precedence.calculate(self, types, trailer, right))
                 break
             types = self.eval_trailer(types, trailer)
     elif element.type in (
             'testlist_star_expr',
             'testlist',
     ):
         # The implicit tuple in statements.
         types = set([iterable.ImplicitTuple(self, element)])
     elif element.type in ('not_test', 'factor'):
         types = self.eval_element(element.children[-1])
         for operator in element.children[:-1]:
             types = set(precedence.factor_calculate(self, types, operator))
     elif element.type == 'test':
         # `x if foo else y` case.
         types = (self.eval_element(element.children[0])
                  | self.eval_element(element.children[-1]))
     elif element.type == 'operator':
         # Must be an ellipsis, other operators are not evaluated.
         assert element.value == '...'
         types = set([compiled.create(self, Ellipsis)])
     elif element.type == 'dotted_name':
         types = self._eval_atom(element.children[0])
         for next_name in element.children[2::2]:
             types = set(
                 chain.from_iterable(
                     self.find_types(typ, next_name) for typ in types))
         types = types
     elif element.type == 'eval_input':
         types = self._eval_element_not_cached(element.children[0])
     elif element.type == 'annassign':
         types = self.eval_element(element.children[1])
     else:
         types = precedence.calculate_children(self, element.children)
     debug.dbg('eval_element result %s', types)
     return types
Example #8
0
        def calculate_children(evaluator, children):
            """
            Calculate a list of children with operators.
            """
            iterator = iter(children)
            types = evaluator.eval_element(next(iterator))
            for operator in iterator:
                try:  # PATCH: Catches StopIteration error
                    right = next(iterator)
                    if tree.is_node(operator, 'comp_op'):  # not in / is not
                        operator = ' '.join(str(c.value) for c in
                                            operator.children)

                    # handle lazy evaluation of and/or here.
                    if operator in ('and', 'or'):
                        left_bools = set([left.py__bool__() for left in types])
                        if left_bools == set([True]):
                            if operator == 'and':
                                types = evaluator.eval_element(right)
                        elif left_bools == set([False]):
                            if operator != 'and':
                                types = evaluator.eval_element(right)
                        # Otherwise continue, because of uncertainty.
                    else:
                        types = calculate(evaluator, types, operator,
                                          evaluator.eval_element(right))
                except StopIteration:
                    debug.warning('calculate_children StopIteration %s', types)
            debug.dbg('calculate_children types %s', types)
            return types
Example #9
0
 def _eval_element_not_cached(self, context, element):
     debug.dbg('eval_element %s@%s', element, element.start_pos)
     types = set()
     typ = element.type
     if typ in ('name', 'number', 'string', 'atom'):
         types = self.eval_atom(context, element)
     elif typ == 'keyword':
         # For False/True/None
         if element.value in ('False', 'True', 'None'):
             types.add(compiled.builtin_from_name(self, element.value))
         # else: print e.g. could be evaluated like this in Python 2.7
     elif typ == 'lambdef':
         types = set([er.FunctionContext(self, context, element)])
     elif typ == 'expr_stmt':
         types = self.eval_statement(context, element)
     elif typ in ('power', 'atom_expr'):
         first_child = element.children[0]
         if not (first_child.type == 'keyword' and first_child.value == 'await'):
             types = self.eval_atom(context, first_child)
             for trailer in element.children[1:]:
                 if trailer == '**':  # has a power operation.
                     right = self.eval_element(context, element.children[2])
                     types = set(precedence.calculate(self, context, types, trailer, right))
                     break
                 types = self.eval_trailer(context, types, trailer)
     elif typ in ('testlist_star_expr', 'testlist',):
         # The implicit tuple in statements.
         types = set([iterable.SequenceLiteralContext(self, context, element)])
     elif typ in ('not_test', 'factor'):
         types = self.eval_element(context, element.children[-1])
         for operator in element.children[:-1]:
             types = set(precedence.factor_calculate(self, types, operator))
     elif typ == 'test':
         # `x if foo else y` case.
         types = (self.eval_element(context, element.children[0]) |
                  self.eval_element(context, element.children[-1]))
     elif typ == 'operator':
         # Must be an ellipsis, other operators are not evaluated.
         # In Python 2 ellipsis is coded as three single dot tokens, not
         # as one token 3 dot token.
         assert element.value in ('.', '...')
         types = set([compiled.create(self, Ellipsis)])
     elif typ == 'dotted_name':
         types = self.eval_atom(context, element.children[0])
         for next_name in element.children[2::2]:
             # TODO add search_global=True?
             types = unite(
                 typ.py__getattribute__(next_name, name_context=context)
                 for typ in types
             )
         types = types
     elif typ == 'eval_input':
         types = self._eval_element_not_cached(context, element.children[0])
     elif typ == 'annassign':
         types = pep0484._evaluate_for_annotation(context, element.children[1])
     else:
         types = precedence.calculate_children(self, context, element.children)
     debug.dbg('eval_element result %s', types)
     return types
Example #10
0
    def _eval_atom(self, atom):
        """
        Basically to process ``atom`` nodes. The parser sometimes doesn't
        generate the node (because it has just one child). In that case an atom
        might be a name or a literal as well.
        """
        if isinstance(atom, tree.Name):
            # This is the first global lookup.
            stmt = atom.get_definition()
            scope = stmt.get_parent_until(tree.IsScope, include_current=True)
            if isinstance(scope, (tree.Function, er.FunctionExecution)):
                # Adjust scope: If the name is not in the suite, it's a param
                # default or annotation and will be resolved as part of the
                # parent scope.
                colon = scope.children.index(':')
                if atom.start_pos < scope.children[colon + 1].start_pos:
                    scope = scope.get_parent_scope()
            if isinstance(stmt, tree.CompFor):
                stmt = stmt.get_parent_until((tree.ClassOrFunc, tree.ExprStmt))
            if stmt.type != 'expr_stmt':
                # We only need to adjust the start_pos for statements, because
                # there the name cannot be used.
                stmt = atom
            return self.find_types(scope,
                                   atom,
                                   stmt.start_pos,
                                   search_global=True)
        elif isinstance(atom, tree.Literal):
            return set([compiled.create(self, atom.eval())])
        else:
            c = atom.children
            if c[0].type == 'string':
                # Will be one string.
                types = self._eval_atom(c[0])
                for string in c[1:]:
                    right = self._eval_atom(string)
                    types = precedence.calculate(self, types, '+', right)
                return types
            # Parentheses without commas are not tuples.
            elif c[0] == '(' and not len(c) == 2 \
                    and not(tree.is_node(c[1], 'testlist_comp')
                            and len(c[1].children) > 1):
                return self.eval_element(c[1])

            try:
                comp_for = c[1].children[1]
            except (IndexError, AttributeError):
                pass
            else:
                if comp_for == ':':
                    # Dict comprehensions have a colon at the 3rd index.
                    try:
                        comp_for = c[1].children[3]
                    except IndexError:
                        pass

                if comp_for.type == 'comp_for':
                    return set([iterable.Comprehension.from_atom(self, atom)])
            return set([iterable.Array(self, atom)])
Example #11
0
    def _eval_stmt(self, context, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `tree.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        rhs = stmt.get_rhs()
        types = self.eval_element(context, rhs)

        if seek_name:
            c_node = ContextualizedName(context, seek_name)
            types = finder.check_tuple_assignments(self, c_node, types)

        first_operation = stmt.first_operation()
        if first_operation not in ('=', None) and first_operation.type == 'operator':
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            left = context.py__getattribute__(
                name, position=stmt.start_pos, search_global=True)

            for_stmt = tree.search_ancestor(stmt, 'for_stmt')
            if for_stmt is not None and for_stmt.type == 'for_stmt' and types \
                    and for_stmt.defines_one_name():
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable. Also only do it, if the variable is not a tuple.
                node = for_stmt.get_input_node()
                cn = ContextualizedNode(context, node)
                ordered = list(iterable.py__iter__(self, cn.infer(), cn))

                for lazy_context in ordered:
                    dct = {str(for_stmt.children[1]): lazy_context.infer()}
                    with helpers.predefine_names(context, for_stmt, dct):
                        t = self.eval_element(context, rhs)
                        left = precedence.calculate(self, context, left, operator, t)
                types = left
            else:
                types = precedence.calculate(self, context, left, operator, types)
        debug.dbg('eval_statement result %s', types)
        return types
Example #12
0
    def eval_statement(self, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `pr.Statement`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        expression_list = stmt.expression_list()
        if isinstance(stmt, FakeStatement):
            return expression_list  # Already contains the results.

        result = self.eval_expression_list(expression_list)

        ass_details = stmt.assignment_details
        if ass_details and ass_details[0][1] != '=' and not isinstance(
                stmt, er.InstanceElement):  # TODO don't check for this.
            expr_list, operator = ass_details[0]
            # `=` is always the last character in aug assignments -> -1
            operator = operator[:-1]
            name = str(expr_list[0].name)
            parent = stmt.parent
            if isinstance(parent, (pr.SubModule, fast.Module)):
                parent = er.ModuleWrapper(self, parent)
            left = self.find_types(parent, name, stmt.start_pos)
            if isinstance(stmt.parent, pr.ForFlow):
                # iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable.
                for r in result:
                    left = precedence.calculate(self, left, operator, [r])
                result = left
            else:
                result = precedence.calculate(self, left, operator, result)
        elif len(stmt.get_defined_names()) > 1 and seek_name and ass_details:
            # Assignment checking is only important if the statement defines
            # multiple variables.
            new_result = []
            for ass_expression_list, op in ass_details:
                new_result += finder.find_assignments(ass_expression_list[0],
                                                      result, seek_name)
            result = new_result
        return result
Example #13
0
    def eval_statement(self, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `pr.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        expression_list = stmt.expression_list()
        if isinstance(stmt, FakeStatement):
            return expression_list  # Already contains the results.

        result = self.eval_expression_list(expression_list)

        ass_details = stmt.assignment_details
        if ass_details and ass_details[0][1] != '=' and not isinstance(stmt, er.InstanceElement):  # TODO don't check for this.
            expr_list, _operator = ass_details[0]
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(_operator)
            operator.string = operator.string[:-1]
            name = str(expr_list[0].name)
            parent = stmt.parent.get_parent_until(pr.Flow, reverse=True)
            if isinstance(parent, (pr.SubModule, fast.Module)):
                parent = er.ModuleWrapper(self, parent)
            left = self.find_types(parent, name, stmt.start_pos)
            if isinstance(stmt.parent, pr.ForFlow):
                # iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable.
                for r in result:
                    left = precedence.calculate(self, left, operator, [r])
                result = left
            else:
                result = precedence.calculate(self, left, operator, result)
        elif len(stmt.get_defined_names()) > 1 and seek_name and ass_details:
            # Assignment checking is only important if the statement defines
            # multiple variables.
            new_result = []
            for ass_expression_list, op in ass_details:
                new_result += finder.find_assignments(ass_expression_list[0], result, seek_name)
            result = new_result
        return result
Example #14
0
    def _eval_atom(self, atom):
        """
        Basically to process ``atom`` nodes. The parser sometimes doesn't
        generate the node (because it has just one child). In that case an atom
        might be a name or a literal as well.
        """
        if isinstance(atom, tree.Name):
            # This is the first global lookup.
            stmt = atom.get_definition()
            scope = stmt.get_parent_until(tree.IsScope, include_current=True)
            if isinstance(scope, (tree.Function, er.FunctionExecution)):
                # Adjust scope: If the name is not in the suite, it's a param
                # default or annotation and will be resolved as part of the
                # parent scope.
                colon = scope.children.index(':')
                if atom.start_pos < scope.children[colon + 1].start_pos:
                    scope = scope.get_parent_scope()
            if isinstance(stmt, tree.CompFor):
                stmt = stmt.get_parent_until((tree.ClassOrFunc, tree.ExprStmt))
            if stmt.type != 'expr_stmt':
                # We only need to adjust the start_pos for statements, because
                # there the name cannot be used.
                stmt = atom
            return self.find_types(scope, atom, stmt.start_pos, search_global=True)
        elif isinstance(atom, tree.Literal):
            return set([compiled.create(self, atom.eval())])
        else:
            c = atom.children
            if c[0].type == 'string':
                # Will be one string.
                types = self._eval_atom(c[0])
                for string in c[1:]:
                    right = self._eval_atom(string)
                    types = precedence.calculate(self, types, '+', right)
                return types
            # Parentheses without commas are not tuples.
            elif c[0] == '(' and not len(c) == 2 \
                    and not(tree.is_node(c[1], 'testlist_comp')
                            and len(c[1].children) > 1):
                return self.eval_element(c[1])

            try:
                comp_for = c[1].children[1]
            except (IndexError, AttributeError):
                pass
            else:
                if comp_for == ':':
                    # Dict comprehensions have a colon at the 3rd index.
                    try:
                        comp_for = c[1].children[3]
                    except IndexError:
                        pass

                if comp_for.type == 'comp_for':
                    return set([iterable.Comprehension.from_atom(self, atom)])
            return set([iterable.Array(self, atom)])
Example #15
0
 def _eval_element_not_cached(self, element):
     debug.dbg('eval_element %s@%s', element, element.start_pos)
     types = set()
     if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node(element, 'atom'):
         types = self._eval_atom(element)
     elif isinstance(element, tree.Keyword):
         # For False/True/None
         if element.value in ('False', 'True', 'None'):
             types.add(compiled.builtin_from_name(self, element.value))
         # else: print e.g. could be evaluated like this in Python 2.7
     elif element.isinstance(tree.Lambda):
         types = set([er.LambdaWrapper(self, element)])
     elif element.isinstance(er.LambdaWrapper):
         types = set([element])  # TODO this is no real evaluation.
     elif element.type == 'expr_stmt':
         types = self.eval_statement(element)
     elif element.type in ('power', 'atom_expr'):
         types = self._eval_atom(element.children[0])
         for trailer in element.children[1:]:
             if trailer == '**':  # has a power operation.
                 right = self.eval_element(element.children[2])
                 types = set(precedence.calculate(self, types, trailer, right))
                 break
             types = self.eval_trailer(types, trailer)
     elif element.type in ('testlist_star_expr', 'testlist',):
         # The implicit tuple in statements.
         types = set([iterable.ImplicitTuple(self, element)])
     elif element.type in ('not_test', 'factor'):
         types = self.eval_element(element.children[-1])
         for operator in element.children[:-1]:
             types = set(precedence.factor_calculate(self, types, operator))
     elif element.type == 'test':
         # `x if foo else y` case.
         types = (self.eval_element(element.children[0]) |
                  self.eval_element(element.children[-1]))
     elif element.type == 'operator':
         # Must be an ellipsis, other operators are not evaluated.
         assert element.value == '...'
         types = set([compiled.create(self, Ellipsis)])
     elif element.type == 'dotted_name':
         types = self._eval_atom(element.children[0])
         for next_name in element.children[2::2]:
             types = set(chain.from_iterable(self.find_types(typ, next_name)
                                             for typ in types))
         types = types
     elif element.type == 'eval_input':
         types = self._eval_element_not_cached(element.children[0])
     elif element.type == 'annassign':
         types = self.eval_element(element.children[1])
     else:
         types = precedence.calculate_children(self, element.children)
     debug.dbg('eval_element result %s', types)
     return types
Example #16
0
 def _eval_precedence(self, _precedence):
     left = self._process_precedence_element(_precedence.left)
     right = self._process_precedence_element(_precedence.right)
     return precedence.calculate(left, _precedence.operator, right)
Example #17
0
 def _eval_precedence(self, _precedence):
     left = self.process_precedence_element(_precedence.left)
     right = self.process_precedence_element(_precedence.right)
     return precedence.calculate(self, left, _precedence.operator, right)
Example #18
0
    def eval_atom(self, context, atom):
        """
        Basically to process ``atom`` nodes. The parser sometimes doesn't
        generate the node (because it has just one child). In that case an atom
        might be a name or a literal as well.
        """
        if atom.type == 'name':
            # This is the first global lookup.
            stmt = atom.get_definition()
            if stmt.type == 'comp_for':
                stmt = tree.search_ancestor(
                    stmt, ('expr_stmt', 'lambda', 'funcdef', 'classdef'))
            if stmt is None or stmt.type != 'expr_stmt':
                # We only need to adjust the start_pos for statements, because
                # there the name cannot be used.
                stmt = atom
            return context.py__getattribute__(name_or_str=atom,
                                              position=stmt.start_pos,
                                              search_global=True)
        elif isinstance(atom, tree.Literal):
            return set([compiled.create(self, atom.eval())])
        else:
            c = atom.children
            if c[0].type == 'string':
                # Will be one string.
                types = self.eval_atom(context, c[0])
                for string in c[1:]:
                    right = self.eval_atom(context, string)
                    types = precedence.calculate(self, context, types, '+',
                                                 right)
                return types
            # Parentheses without commas are not tuples.
            elif c[0] == '(' and not len(c) == 2 \
                    and not(c[1].type == 'testlist_comp' and
                            len(c[1].children) > 1):
                return self.eval_element(context, c[1])

            try:
                comp_for = c[1].children[1]
            except (IndexError, AttributeError):
                pass
            else:
                if comp_for == ':':
                    # Dict comprehensions have a colon at the 3rd index.
                    try:
                        comp_for = c[1].children[3]
                    except IndexError:
                        pass

                if comp_for.type == 'comp_for':
                    return set([
                        iterable.Comprehension.from_atom(self, context, atom)
                    ])

            # It's a dict/list/tuple literal.
            array_node = c[1]
            try:
                array_node_c = array_node.children
            except AttributeError:
                array_node_c = []
            if c[0] == '{' and (array_node == '}' or ':' in array_node_c):
                context = iterable.DictLiteralContext(self, context, atom)
            else:
                context = iterable.SequenceLiteralContext(self, context, atom)
            return set([context])
Example #19
0
    def eval_atom(self, context, atom):
        """
        Basically to process ``atom`` nodes. The parser sometimes doesn't
        generate the node (because it has just one child). In that case an atom
        might be a name or a literal as well.
        """
        if atom.type == 'name':
            # This is the first global lookup.
            stmt = atom.get_definition()
            if stmt.type == 'comp_for':
                stmt = tree.search_ancestor(stmt, ('expr_stmt', 'lambda', 'funcdef', 'classdef'))
            if stmt is None or stmt.type != 'expr_stmt':
                # We only need to adjust the start_pos for statements, because
                # there the name cannot be used.
                stmt = atom
            return context.py__getattribute__(
                name_or_str=atom,
                position=stmt.start_pos,
                search_global=True
            )
        elif isinstance(atom, tree.Literal):
            return set([compiled.create(self, atom.eval())])
        else:
            c = atom.children
            if c[0].type == 'string':
                # Will be one string.
                types = self.eval_atom(context, c[0])
                for string in c[1:]:
                    right = self.eval_atom(context, string)
                    types = precedence.calculate(self, context, types, '+', right)
                return types
            # Parentheses without commas are not tuples.
            elif c[0] == '(' and not len(c) == 2 \
                    and not(c[1].type == 'testlist_comp' and
                            len(c[1].children) > 1):
                return self.eval_element(context, c[1])

            try:
                comp_for = c[1].children[1]
            except (IndexError, AttributeError):
                pass
            else:
                if comp_for == ':':
                    # Dict comprehensions have a colon at the 3rd index.
                    try:
                        comp_for = c[1].children[3]
                    except IndexError:
                        pass

                if comp_for.type == 'comp_for':
                    return set([iterable.Comprehension.from_atom(self, context, atom)])

            # It's a dict/list/tuple literal.
            array_node = c[1]
            try:
                array_node_c = array_node.children
            except AttributeError:
                array_node_c = []
            if c[0] == '{' and (array_node == '}' or ':' in array_node_c):
                context = iterable.DictLiteralContext(self, context, atom)
            else:
                context = iterable.SequenceLiteralContext(self, context, atom)
            return set([context])