Exemple #1
0
 def visit_BinOp(self, node):
     self.generic_visit(node)
     if isinstance(node.op, BitAnd):
         return BoolOp(And(), (node.left, node.right))
     elif isinstance(node.op, BitOr):
         return BoolOp(Or(), (node.left, node.right))
     else:
         raise TypeError("unsupported operation '%s'" %
                         node.op.__class__.__name__)
Exemple #2
0
    def insert_with_block_check(self, node):
        """Modifies a with statement node in-place to add an initial check
        for whether or not the block should be executed. If the block is
        not executed it will raise a XonshBlockError containing the required
        information.
        """
        nwith = self._nwith  # the nesting level of the current with-statement
        lineno = get_lineno(node)
        col = get_col(node, 0)
        # Add or discover target names
        targets = set()
        i = 0  # index of unassigned items

        def make_next_target():
            nonlocal i
            targ = '__xonsh_with_target_{}_{}__'.format(nwith, i)
            n = Name(id=targ, ctx=Store(), lineno=lineno, col_offset=col)
            targets.add(targ)
            i += 1
            return n
        for item in node.items:
            if item.optional_vars is None:
                if has_elts(item.context_expr):
                    targs = [make_next_target() for _ in item.context_expr.elts]
                    optvars = Tuple(elts=targs, ctx=Store(), lineno=lineno,
                                    col_offset=col)
                else:
                    optvars = make_next_target()
                item.optional_vars = optvars
            else:
                targets.update(gather_names(item.optional_vars))
        # Ok, now that targets have been found / created, make the actual check
        # to see if we are in a non-executing block. This is equivalent to
        # writing the following condition:
        #
        #     if getattr(targ0, '__xonsh_block__', False) or \
        #        getattr(targ1, '__xonsh_block__', False) or ...:
        #         raise XonshBlockError(lines, globals(), locals())
        tests = [_getblockattr(t, lineno, col) for t in sorted(targets)]
        if len(tests) == 1:
            test = tests[0]
        else:
            test = BoolOp(op=Or(), values=tests, lineno=lineno, col_offset=col)
        ldx, udx = self._find_with_block_line_idx(node)
        lines = [Str(s=s, lineno=lineno, col_offset=col)
                 for s in self.lines[ldx:udx]]
        check = If(test=test, body=[
            Raise(exc=xonsh_call('XonshBlockError',
                                 args=[List(elts=lines, ctx=Load(),
                                            lineno=lineno, col_offset=col),
                                       xonsh_call('globals', args=[],
                                                  lineno=lineno, col=col),
                                       xonsh_call('locals', args=[],
                                                  lineno=lineno, col=col)],
                                 lineno=lineno, col=col),
                  cause=None, lineno=lineno, col_offset=col)],
                orelse=[], lineno=lineno, col_offset=col)
        node.body.insert(0, check)
Exemple #3
0
 def compBreaker(self, node):
     assert isinstance(node, Compare)
     if len(node.comparators) == 1:
         return node
     else:
         comp1 = Compare(node.left, node.ops[0:1], node.comparators[0:1])
         comp2 = Compare(node.comparators[0], node.ops[1:],
                         node.comparators[1:])
         newNode = BoolOp(And(), [comp1, self.compBreaker(comp2)])
         return newNode
Exemple #4
0
    def _get_all_names(
        self,
        node: ast.BoolOp,
    ) -> List[str]:
        # That's an ugly hack to make sure that we do not visit
        # one chained `BoolOp` elements twice. Sorry!
        node._wps_visited = True  # type: ignore  # noqa: Z441

        names = []
        for operand in node.values:
            if isinstance(operand, ast.BoolOp):
                names.extend(self._get_all_names(operand))
            else:
                names.append(astor.to_source(operand))
        return names
Exemple #5
0
    def visit_BoolOp(self, bool_op: ast.BoolOp) -> Optional[IType]:
        """
        Verifies if the types of the operands are valid to the boolean operations

        If the operations are valid, changes de Python operator by the Boa operator in the syntax tree

        :param bool_op: the python ast boolean operation node
        :return: the type of the result of the operation if the operation is valid. Otherwise, returns None
        :rtype: IType or None
        """
        lineno: int = bool_op.lineno
        col_offset: int = bool_op.col_offset
        try:
            return_type: IType = None
            bool_operation: IOperation = None
            operator: Operator = self.get_operator(bool_op.op)

            if not isinstance(operator, Operator):
                # the operator is invalid or it was not implemented yet
                self._log_error(
                    CompilerError.UnresolvedReference(lineno, col_offset, type(operator).__name__)
                )

            l_operand = self.visit(bool_op.values[0])
            for index, operand in enumerate(bool_op.values[1:]):
                r_operand = self.visit(operand)

                operation: IOperation = self.get_bin_op(operator, r_operand, l_operand)
                if operation is None:
                    self._log_error(
                        CompilerError.NotSupportedOperation(lineno, col_offset, operator)
                    )
                elif bool_operation is None:
                    return_type = operation.result
                    bool_operation = operation

                lineno = operand.lineno
                col_offset = operand.col_offset
                l_operand = r_operand

            bool_op.op = bool_operation
            return return_type
        except CompilerError.MismatchedTypes as raised_error:
            raised_error.line = lineno
            raised_error.col = col_offset
            # raises the exception with the line/col info
            self._log_error(raised_error)
Exemple #6
0
    def _union(self, node):
        values = []
        generated = []

        for union in node:
            for what, sub in union.items():
                if ':' in what:
                    if what in generated:
                        # only generate any imported function once
                        continue
                    generated.append(what)
                    name = what
                    yield self._type(what, name, sub)
                else:
                    # this is a build_in type (and my have been refined)
                    # therefore generate one function per type
                    name = self._unique(what)
                    yield self._function(name, self._type(what, what, sub))

                values += [
                    UnaryOp(
                        op=Not(),
                        operand=Call(
                            func=Name(id=self._python_name(name), ctx=Load()),
                            args=[Name(id='value', ctx=Load())],
                            keywords=[],
                        ),
                    ),
                ]

        yield [
            If(
                test=BoolOp(
                    op=And(),
                    values=values,
                ),
                body=[
                    Return(value=Constant(value=False, kind=None), ),
                ],
                orelse=[],
            ),
        ]
Exemple #7
0
 def transform(tree):
     # Ignore the "lambda e: ...", and descend into the ..., in:
     #   - let[] or letrec[] in tail position.
     #     - letseq[] is a nested sequence of lets, so covers that too.
     #   - do[] in tail position.
     #     - May be generated also by a "with multilambda" block
     #       that has already expanded.
     if islet(tree):
         view = ExpandedLetView(tree)
         assert view.body, "BUG: what's this, a decorator inside a lambda?"
         thelambda = view.body  # lambda e: ...
         thelambda.body = transform(thelambda.body)
     elif isdo(tree):
         thebody = ExpandedDoView(tree).body  # list of do-items
         lastitem = thebody[-1]  # lambda e: ...
         thelambda = lastitem
         thelambda.body = transform(thelambda.body)
     elif type(tree) is Call:
         # Apply TCO to tail calls.
         #   - If already an explicit jump() or loop(), leave it alone.
         #   - If a call to an ec, leave it alone.
         #     - Because an ec call may appear anywhere, a tail-position
         #       analysis will not find all of them.
         #     - This function analyzes only tail positions within
         #       a return-value expression.
         #     - Hence, transform_return() calls us on the content of
         #       all ec nodes directly. ec(...) is like return; the
         #       argument is the retexpr.
         if not (isx(tree.func, _isjump) or isec(tree, known_ecs)):
             tree.args = [tree.func] + tree.args
             tree.func = hq[jump]
             tree = transform_call(tree)
     elif type(tree) is IfExp:
         # Only either body or orelse runs, so both of them are in tail position.
         # test is not in tail position.
         tree.body = transform(tree.body)
         tree.orelse = transform(tree.orelse)
     elif type(tree) is BoolOp:  # and, or
         # and/or is a combined test-and-return. Any number of these may be nested.
         # Because it is in general impossible to know beforehand how many
         # items will be actually evaluated, we define only the last item
         # (in the whole expression) to be in tail position.
         if type(tree.values[-1]) in (Call, IfExp,
                                      BoolOp):  # must match above handlers
             # other items: not in tail position, compute normally
             if len(tree.values) > 2:
                 op_of_others = BoolOp(op=tree.op,
                                       values=tree.values[:-1],
                                       lineno=tree.lineno,
                                       col_offset=tree.col_offset)
             else:
                 op_of_others = tree.values[0]
             if type(tree.op) is Or:
                 # or(data1, ..., datan, tail) --> it if any(others) else tail
                 tree = aif(
                     Tuple(elts=[
                         op_of_others,
                         transform_data(
                             Name(id="it",
                                  lineno=tree.lineno,
                                  col_offset=tree.col_offset)),
                         transform(tree.values[-1])
                     ],
                           lineno=tree.lineno,
                           col_offset=tree.col_offset))  # tail-call item
             elif type(tree.op) is And:
                 # and(data1, ..., datan, tail) --> tail if all(others) else False
                 fal = q[False]
                 fal = copy_location(fal, tree)
                 tree = IfExp(test=op_of_others,
                              body=transform(tree.values[-1]),
                              orelse=transform_data(fal))
             else:  # cannot happen
                 assert False, "unknown BoolOp type {}".format(
                     tree.op)  # pragma: no cover
         else:  # optimization: BoolOp, no call or compound in tail position --> treat as single data item
             tree = transform_data(tree)
     else:
         tree = transform_data(tree)
     return tree
    def handle_f(self, f):
        # Do we need to use .attname here?
        # What about transforms/lookups?
        f.contains_aggregate = False
        if "__" in f.name:
            # We need to chain a bunch of attr lookups, returning None
            # if any of them give us a None, we should be returning a None.
            #

            # .  while x is not None and parts:
            # .      x = getattr(x, parts.pop(0), None)
            #   return x
            return [
                Assign(targets=[Name(id="source", **self.file_store)],
                       value=Name(id="self", **self.file),
                       **self.file),
                Assign(
                    targets=[Name(id="parts", **self.file_store)],
                    value=Call(
                        func=Attribute(value=Constant(value=f.name,
                                                      **self.file),
                                       attr="split",
                                       **self.file),
                        args=[Constant(value="__", **self.file)],
                        keywords=[],
                        kwonlyargs=[],
                        **self.file,
                    ),
                    **self.file,
                ),
                While(
                    test=BoolOp(
                        op=And(),
                        values=[
                            Compare(
                                left=Name(id="source", **self.file),
                                ops=[IsNot()],
                                comparators=[
                                    Constant(value=None, **self.file)
                                ],
                                **self.file,
                            ),
                            Name(id="parts", **self.file),
                        ],
                        **self.file,
                    ),
                    body=[
                        Assign(
                            targets=[Name(id="source", **self.file_store)],
                            value=Call(
                                func=Name(id="getattr", **self.file),
                                args=[
                                    Name(id="source", **self.file),
                                    Call(
                                        func=Attribute(value=Name(id="parts",
                                                                  **self.file),
                                                       attr="pop",
                                                       **self.file),
                                        args=[Constant(value=0, **self.file)],
                                        keywords=[],
                                        kwonlyargs=[],
                                        **self.file,
                                    ),
                                    Constant(value=None, **self.file),
                                ],
                                keywords=[],
                                kwonlyargs=[],
                                **self.file,
                            ),
                            **self.file,
                        ),
                    ],
                    orelse=[],
                    **self.file,
                ),
                Return(value=Name(id="source", **self.file), **self.file),
            ]
        return Attribute(value=Name(id="self", **self.file),
                         attr=f.name,
                         **self.file)