Ejemplo n.º 1
0
    def _setbindings(self, newbindings):
        t = self._type
        if t in ("decorator", "lispy_expr"):
            if t == "decorator":
                # dlet[...], blet[...]
                # dlet(...), blet(...)
                thetree = self._tree
            else:  # "lispy_expr"
                # (let[...])[...]
                # (let(...))[...]
                # ^^^^^^^^^^
                thetree = self._tree.value

            if type(
                    thetree
            ) is Call:  # parenthesis syntax for macro arguments  TODO: Python 3.9+: remove once we bump minimum Python to 3.9
                thetree.args = newbindings
                return
            _set_subscript_slice(thetree, Tuple(elts=newbindings))
        else:
            theexpr = self._theexpr_ref()
            if t == "in_expr":
                theexpr.left = Tuple(elts=newbindings)
            elif t == "where_expr":
                thewhere = theexpr.elts[1]
                if type(thewhere) is Call:
                    thewhere.args = newbindings
                else:  # Subscript
                    _set_subscript_slice(thewhere, Tuple(elts=newbindings))
Ejemplo n.º 2
0
 def test_get_value(self) -> None:
     """Tests get_value succeeds"""
     val = "foo"
     self.assertEqual(get_value(Str(s=val, constant_value=None, string=None)), val)
     self.assertEqual(
         get_value(Constant(value=val, constant_value=None, string=None)), val
     )
     self.assertIsInstance(get_value(Tuple(expr=None)), Tuple)
     self.assertIsInstance(get_value(Tuple(expr=None)), Tuple)
     self.assertIsNone(get_value(Name(None, None)))
     self.assertEqual(get_value(get_value(ast.parse("-5").body[0])), -5)
Ejemplo n.º 3
0
def _canonize_bindings(elts, locref, allow_call_in_name_position=False):
    """Wrap a single binding without container into a length-1 list.

    Pass through multiple bindings as-is.

    Yell if the input format is invalid.

    elts: list of bindings, either::
        [(k0, v0), ...]   # multiple bindings
        [(k, v)]          # single binding also ok
        [k, v]            # special single binding format, missing container

    locref: AST node to copy location information from, in case we need to
    make a wrapper for a single binding.

    allow_call_in_name_position: used by let_syntax to allow template definitions.
    """
    def iskey(x):
        return type(x) is Name or \
               allow_call_in_name_position and type(x) is Call and type(x.func) is Name

    if len(elts) == 2 and iskey(elts[0]):
        return [
            Tuple(elts=elts,
                  lineno=locref.lineno,
                  col_offset=locref.col_offset)
        ]
    if all((type(b) is Tuple and len(b.elts) == 2 and iskey(b.elts[0]))
           for b in elts):
        return elts
    assert False, "expected bindings to be ((k0, v0), ...) or a single (k, v)"
Ejemplo n.º 4
0
def add_method_call(
    body: List, instance: str, method: str, args: List, kwargs: List, returns: List[str], index: Optional[int] = None
) -> None:
    """Adds method call to be body of a container. By default, it appends. When
    index is specified, it inserts.

    :param body:
    :param instance:
    :param method:
    :param args:
    :param kwargs:
    :param index:
    :param returns:
    :return:
    """

    call = Call(func=get_name_attr(instance, method), args=args, keywords=kwargs)

    cont: Union[Expr, Assign, None] = None

    if not returns:
        cont = Expr(value=call)
    elif len(returns) == 1:
        # TODO AnnAssign??
        cont = Assign(targets=[Name(id=returns[0], ctx=Store())], value=call)
    else:
        cont = Assign(targets=[Tuple(elts=[Name(id=ret, ctx=Store()) for ret in returns], ctx=Store())], value=call)

    if index is None:
        body.append(cont)
    else:
        body.insert(index, cont)
Ejemplo n.º 5
0
    def _split_set_elts(elts):  # pylint: disable=C0111
        collapsed = []
        for element in elts:
            if isinstance(element, BinOp) and isinstance(element.op, BitOr):
                collapsed.extend(NotationASTTransformer._collapse(element))
            else:
                collapsed.append(element)

        last_choice = []
        choices = [last_choice]
        for element in collapsed:
            if isinstance(element, BitOr):
                last_choice = []
                choices.append(last_choice)
            else:
                last_choice.append(element)

        splitted = []
        for choice in choices:
            if len(choice) > 1:
                splitted.append(Tuple(choice, Load()))
            else:
                splitted.append(choice[0])

        return splitted
Ejemplo n.º 6
0
 def _pattern(pattern):
     left, right = pattern
     if left in ("[]", "_"):
         right = e(f"lambda : {right}")
     else:
         right = e(f"lambda {left} : {right}")
     left = Constant(left)
     return Tuple(elts=[left, right], ctx=Load())
Ejemplo n.º 7
0
 def _trace_print_function(self, existing_node):
     values = existing_node.args
     message_format = 'print(' + ', '.join(['%r'] * len(values)) + ') '
     return self._create_bare_context_call('add_message', [
         BinOp(left=Str(message_format),
               op=Mod(),
               right=Tuple(elts=values, ctx=Load())),
         Num(existing_node.lineno)
     ])
Ejemplo n.º 8
0
def test_ext_slice():
    result = match_ast(pattern, parse('x[0, 1, 2]'))
    actual = deslicify(result['slice'])

    check = match_ast(
        Tuple(
            elts=[Num(n=set(['n1'])),
                  Num(n=set(['n2'])),
                  Num(n=set(['n3']))]), actual)
    assert check == {'n1': 0, 'n2': 1, 'n3': 2}
Ejemplo n.º 9
0
def canonize_bindings(elts, letsyntax_mode=False):  # public as of v0.14.3+
    """Convert any `let` bindings format supported by `unpythonic` into a canonical format.

    Yell if the input format is invalid.

    The canonical format is a `list` of `ast.Tuple`::

        [Tuple(elts=[k0, v0]), ...]

    elts: `list` of bindings, one of::
        [(k0, v0), ...]    # multiple bindings contained in a tuple
        [(k, v),]          # single binding contained in a tuple also ok
        [k, v]             # special single binding format, missing tuple container
        [[k0, v0], ...]    # v0.15.0+: accept also brackets (for consistency)
        [[k, v]]           # v0.15.0+
        [k0 << v0, ...]    # v0.15.0+: accept also env-assignment syntax
        [k << v]           # v0.15.0+

    where the ks and vs are AST nodes.

    letsyntax_mode: used by let_syntax to allow template definitions.
    This allows, beside a bare name `k`, the formats `k(a0, ...)` and `k[a0, ...]`
    to appear in the variable-name position.
    """
    def iskvpairbinding(lst):
        return len(lst) == 2 and _isbindingtarget(lst[0], letsyntax_mode)

    if len(elts) == 1 and isenvassign(elts[0], letsyntax_mode):  # [k << v]
        return [Tuple(elts=[elts[0].left, elts[0].right])]
    if len(elts) == 2 and iskvpairbinding(elts):  # [k, v]
        return [Tuple(elts=elts)]  # TODO: `mcpyrate`: just `q[t[elts]]`?
    if all((type(b) is Tuple and iskvpairbinding(b.elts))
           for b in elts):  # [(k0, v0), ...]
        return elts
    if all((type(b) is List and iskvpairbinding(b.elts))
           for b in elts):  # [[k0, v0], ...]
        return [Tuple(elts=b.elts) for b in elts]
    if all(isenvassign(b, letsyntax_mode) for b in elts):  # [k0 << v0, ...]
        return [Tuple(elts=[b.left, b.right]) for b in elts]
    raise SyntaxError(
        "expected bindings to be `(k0, v0), ...`, `[k0, v0], ...`, or `k0 << v0, ...`, or a single `k, v`, or `k << v`"
    )  # pragma: no cover
Ejemplo n.º 10
0
 def _getbindings(self):
     # Abstract away the namelambda(...). We support both "with curry" and bare formats:
     #   currycall(letter, bindings, currycall(currycall(namelambda, "let_body"), curryf(lambda e: ...)))
     #   letter(bindings, namelambda("let_body")(lambda e: ...))
     thebindings = self._tree.args[1] if self.curried else self._tree.args[0]
     if self.mode == "letrec":
         myelts = []
         if self.curried:
             # "((k, currycall(currycall(namelambda, "letrec_binding_YYY"), curryf(lambda e: ...))), ...)"
             for b in thebindings.elts:
                 k, v = b.elts
                 myelts.append(Tuple(elts=[k, v.args[1].args[0]]))
         else:
             # "((k, namelambda("letrec_binding_YYY")(lambda e: ...)), ...)"
             for b in thebindings.elts:
                 k, v = b.elts
                 myelts.append(Tuple(elts=[k, v.args[0]]))
         return Tuple(elts=myelts)
     else:  # "((k, v), ...)"
         return thebindings
Ejemplo n.º 11
0
def do0(tree):
    if type(tree) not in (Tuple, List):
        assert False, "do0 body: expected a sequence of comma-separated expressions"  # pragma: no cover
    elts = tree.elts
    newelts = []
    newelts.append(q[name["local"][name["_do0_result"] << (ast_literal[elts[0]])]])
    newelts.extend(elts[1:])
    newelts.append(q[name["_do0_result"]])
#    newtree = q[(ast_literal[newelts],)]  # TODO: doesn't work, missing lineno
    newtree = Tuple(elts=newelts, lineno=tree.lineno, col_offset=tree.col_offset)
    return do(newtree)  # do0[] is also just a do[]
Ejemplo n.º 12
0
def _letimpl(bindings, body, mode):
    """bindings: sequence of ast.Tuple: (k1, v1), (k2, v2), ..., (kn, vn)"""
    assert mode in ("let", "letrec")

    body = implicit_do(body)
    if not bindings:
        # Optimize out a `let` with no bindings. The macro layer cannot trigger
        # this case, because our syntaxes always require at least one binding.
        # So this check is here just to protect against use with no bindings directly
        # from other syntax transformers, which in theory could attempt anything.
        #
        # The reason the macro layer never calls us with no bindings is technical.
        # In the macro interface, with no bindings, the macro's `args` are `()`
        # whether it was invoked as `let()[...]` or just `let[...]`. Thus,
        # there is no way to distinguish, in the macro layer, between these
        # two. We can't use `UnexpandedLetView` to do the dirty work of AST
        # analysis, because MacroPy does too much automatically: in the macro
        # layer, `tree` is only the part inside the brackets. So we really
        # can't see whether the part outside the brackets was a Call with no
        # arguments, or just a Name - both cases get treated exactly the same,
        # as a macro invocation with empty `args`.
        #
        # The latter form, `let[...]`, is used by the haskelly syntax
        # `let[(...) in ...]`, `let[..., where(...)]` - and in these cases,
        # both the bindings and the body reside inside the brackets.
        return body  # pragma: no cover
    names, values = zip(*[b.elts for b in bindings])  # --> (k1, ..., kn), (v1, ..., vn)
    names = [k.id for k in names]  # any duplicates will be caught by env at run-time

    e = dyn.gen_sym("e")
    envset = Attribute(value=q[name[e]], attr="set", ctx=Load())

    t = partial(letlike_transform, envname=e, lhsnames=names, rhsnames=names, setter=envset)
    if mode == "letrec":
        values = [t(rhs) for rhs in values]  # RHSs of bindings
        values = [hq[namelambda(u["letrec_binding{}_{}".format(j, lhs)])(ast_literal[rhs])]
                    for j, (lhs, rhs) in enumerate(zip(names, values), start=1)]
    body = t(body)
    body = hq[namelambda(u["{}_body".format(mode)])(ast_literal[body])]

    # CAUTION: letdoutil.py relies on:
    #  - the literal name "letter" to detect expanded let forms
    #  - the "mode" kwarg to detect let/letrec mode
    #  - the absence of an "_envname" kwarg to detect this tree represents a let-expr (vs. a let-decorator),
    #    seeing only the Call node
    #  - the exact AST structure, for the views
    letter = letf
    bindings = [q[(u[k], ast_literal[v])] for k, v in zip(names, values)]
    newtree = hq[letter(ast_literal[Tuple(elts=bindings)], ast_literal[body], mode=u[mode])]
    return newtree
Ejemplo n.º 13
0
 def _trace_print_function(self, existing_node):
     values = list(existing_node.args)
     formats = ['%r'] * len(values)
     if existing_node.starargs is not None:
         values.append(existing_node.starargs)
         formats.append('*%r')
     for keyword in existing_node.keywords:
         values.append(keyword.value)
         formats.append('{}=%r'.format(keyword.arg))
     message_format = 'print(' + ', '.join(formats) + ') '
     return self._create_bare_context_call('add_message',
                                           [BinOp(left=Str(message_format),
                                                  op=Mod(),
                                                  right=Tuple(elts=values,
                                                              ctx=Load())),
                                            Num(existing_node.lineno)])
Ejemplo n.º 14
0
 def test_param2argparse_param_default_ast_tuple(self) -> None:
     """
     Tests that param2argparse_param works to change the type based on the default
       whence said default is an ast.Tuple
     """
     run_ast_test(
         gen_ast=param2argparse_param((
             "byo",
             {
                 "default": Tuple(
                     elts=[],
                     ctx=Load(),
                     expr=None,
                 ),
                 "typ": "str",
             },
         ), ),
         gold=Expr(
             Call(
                 args=[set_value("--byo")],
                 func=Attribute(
                     Name("argument_parser", Load()),
                     "add_argument",
                     Load(),
                 ),
                 keywords=[
                     keyword(arg="type",
                             value=Name("loads", Load()),
                             identifier=None),
                     keyword(arg="required",
                             value=set_value(True),
                             identifier=None),
                     keyword(arg="default",
                             value=set_value("()"),
                             identifier=None),
                 ],
                 expr=None,
                 expr_func=None,
             )),
         test_case_instance=self,
     )