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))
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)
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)"
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)
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
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())
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) ])
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}
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
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
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[]
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
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)])
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, )