def wrapper(hy_compiler, *args): if shadow and any(is_unpack("iterable", x) for x in args): # Try a shadow function call with this name instead. return Expression([Symbol("hy.pyops." + name), *args]).replace(hy_compiler.this) expr = hy_compiler.this root = unmangle(expr[0]) if py_version_required and sys.version_info < py_version_required: raise hy_compiler._syntax_error( expr, "`{}` requires Python {} or later".format( root, ".".join(map(str, py_version_required))), ) try: parse_tree = pattern.parse(args) except NoParseError as e: raise hy_compiler._syntax_error( expr[min(e.state.pos + 1, len(expr) - 1)], "parse error for pattern macro '{}': {}".format( root, e.msg.replace("<EOF>", "end of form")), ) return fn(hy_compiler, expr, root, *parse_tree)
def _compile_collect(self, exprs, with_kwargs=False, dict_display=False): """Collect the expression contexts from a list of compiled expression. This returns a list of the expression contexts, and the sum of the Result objects passed as arguments. """ compiled_exprs = [] ret = Result() keywords = [] exprs_iter = iter(exprs) for expr in exprs_iter: if is_unpack("mapping", expr): ret += self.compile(expr[1]) if dict_display: compiled_exprs.append(None) compiled_exprs.append(ret.force_expr) elif with_kwargs: keywords.append( asty.keyword(expr, arg=None, value=ret.force_expr)) elif with_kwargs and isinstance(expr, Keyword): if keyword.iskeyword(expr.name): raise self._syntax_error( expr, "keyword argument cannot be Python reserved word") try: value = next(exprs_iter) except StopIteration: raise self._syntax_error( expr, "Keyword argument {kw} needs a value.".format(kw=expr)) if not expr: raise self._syntax_error( expr, "Can't call a function with the empty keyword") compiled_value = self.compile(value) ret += compiled_value arg = str(expr)[1:] keywords.append( asty.keyword(expr, arg=mangle(arg), value=compiled_value.force_expr)) else: ret += self.compile(expr) compiled_exprs.append(ret.force_expr) return compiled_exprs, ret, keywords
def compile_expression(self, expr, *, allow_annotation_expression=False): # Perform macro expansions expr = macroexpand(expr, self.module, self) if isinstance(expr, (Result, ast.AST)): # Use this as-is. return expr elif not isinstance(expr, Expression): # Go through compile again if we have a different type of model. return self.compile(expr) if not expr: raise self._syntax_error( expr, "empty expressions are not allowed at top level" ) args = list(expr) root = args.pop(0) func = None if isinstance(root, Symbol) and root.startswith("."): # (.split "test test") -> "test test".split() # (.a.b.c x v1 v2) -> (.c (. x a b) v1 v2) -> x.a.b.c(v1, v2) # Get the method name (the last named attribute # in the chain of attributes) attrs = [ Symbol(a).replace(root) if a else None for a in root.split(".")[1:] ] if not all(attrs): raise self._syntax_error(expr, "cannot access empty attribute") root = attrs.pop() # Get the object we're calling the method on # (extracted with the attribute access DSL) # Skip past keywords and their arguments. try: kws, obj, rest = ( many(KEYWORD + FORM | unpack("mapping")) + FORM + many(FORM) ).parse(args) except NoParseError: raise self._syntax_error(expr, "attribute access requires object") # Reconstruct `args` to exclude `obj`. args = [x for p in kws for x in p] + list(rest) if is_unpack("iterable", obj): raise self._syntax_error( obj, "can't call a method on an unpacking form" ) func = self.compile(Expression([Symbol(".").replace(root), obj] + attrs)) # And get the method func += asty.Attribute( root, value=func.force_expr, attr=mangle(root), ctx=ast.Load() ) if is_annotate_expression(root): # Flatten and compile the annotation expression. ann_expr = Expression(root + args).replace(root) return self.compile_expression(ann_expr, allow_annotation_expression=True) if not func: func = self.compile(root) args, ret, keywords = self._compile_collect(args, with_kwargs=True) return ( func + ret + asty.Call(expr, func=func.expr, args=args, keywords=keywords) )