Repository: JuliaLang/julia
File: stdlib/InteractiveUtils/src/macros.jl (Julia)

Code before:
        args = [#=__source__::=#LineNumberNode, #=__module__::=#Module, Core.Typeof.(ex0.args[3:end])...]
        return gen_call(fcn, Any[ex0.args[1], Ref.(args)...], where_params, kws; use_signature_tuple)
    end

    ex = Meta.lower(__module__, ex0)
    if !isa(ex, Expr)
        return Expr(:call, :error, "expression is not a function call or symbol")
    end

    if ex.head === :thunk || exret.head === :none
        return Expr(:call, :error, "expression is not a function call, "
                                  * "or is too complex for @$fcn to analyze; "
                                  * "break it down to simpler parts if possible. "
                                  * "In some cases, you may want to use Meta.@lower.")
    end
    return Expr(:none)
end

"""
Same behaviour as `gen_call_with_extracted_types` except that keyword arguments
of the form "foo=bar" are passed on to the called function as well.
The keyword arguments must be given before the mandatory argument.
"""
function gen_call_with_extracted_types_and_kwargs(__module__, fcn, ex0; is_source_reflection = !is_code_macro(fcn), supports_binding_reflection = false, use_signature_tuple = false)
    kws = Expr[]
    arg = ex0[end] # Mandatory argument
    for i in 1:length(ex0)-1
        x = ex0[i]
        if x isa Expr && x.head === :(=) # Keyword given of the form "foo=bar"
            if length(x.args) != 2
                return Expr(:call, :error, "Invalid keyword argument: $x")
            end
            push!(kws, Expr(:kw, esc(x.args[1]), esc(x.args[2])))
        else
            return Expr(:call, :error, "@$fcn expects only one non-keyword argument")
        end
    end
    return gen_call_with_extracted_types(__module__, fcn, arg, kws; is_source_reflection, supports_binding_reflection, use_signature_tuple)
end

for fname in [:which, :less, :edit, :functionloc]
    @eval begin
        macro ($fname)(ex0)
            gen_call_with_extracted_types(__module__, $(Expr(:quote, fname)), ex0, Expr[];
                                          is_source_reflection = true,
                                          supports_binding_reflection = $(fname === :which))
        end
    end
end

macro which(ex0::Symbol)

Review comment (suggestion):
This should probably document how `use_signature_tuple` affects the generated code / called function, but the edit to the error above will also help folks understand that this places interface requirements on `fcn`

Code after:
then carry on using this function. For example, for the input expression `a .+ b`, we emit the anonymous function
`(a, b) -> a .+ b` then call `fcn` just as if the user had issued a call to this anonymous function. That should be the
desired behavior for most macros that want to map an expression to the corresponding generated code, as in `@code_typed`
or `@code_llvm` for instance.

## Binding reflection

Expressions of the form `a.b` (or `a.b.c` and so on) are by default interpreted as calls to `getproperty`.
However, if the value corresponding to the left-hand side (`a`, `a.b`, etc) is a module, some implementations
may instead be interested in the binding lookup, instead of the function call. If that is the case,
`supports_binding_reflection` may be set to `true` which will emit a call to `fcn(a, :b)` (or `fcn(a.b, :c)` etc).

## Tuple signature type

If `use_signature_tuple = true`, then a single tuple consisting of `Tuple{ft, argtypes...}` will be formed
and provided to `fcn`. `fcn` is then expected to use `ft` as the callable type with no further transformation.

This behavior is required to enable support type-annotated callable objects.

To understand this requirement, we'll use `code_typed` as an example. `code_typed(f, ())` interprets its input as the signature
`Tuple{typeof(f)}`, and `code_typed(Returns{Int}, ())` interprets that as the signature `Tuple{Type{Returns{Int}}}`, corresponding
to the type constructor.
To remove the ambiguity, `code_typed` must support an implementation that directly accepts a function type. This implementation
is assumed to be the method for `fcn(sigt::Type{<:Tuple})`.
"""
function gen_call_with_extracted_types(__module__, fcn, ex0, kws = Expr[]; is_source_reflection = !is_code_macro(fcn), supports_binding_reflection = false, use_signature_tuple = false)
    # Ignore assignments (e.g. `@edit a = f(x)` gets turned into `@edit f(x)`)
    if isa(ex0, Expr) && ex0.head === :(=) && isa(ex0.args[1], Symbol)
        return gen_call_with_extracted_types(__module__, fcn, ex0.args[2], kws; is_source_reflection, supports_binding_reflection, use_signature_tuple)
    end
    where_params = nothing
    if isa(ex0, Expr)
        ex0, where_params = extract_where_parameters(ex0)
    end
    if isa(ex0, Expr)
        if ex0.head === :do && isexpr(get(ex0.args, 1, nothing), :call)
            # Normalize `f(args...) do ... end` calls to `f(do_anonymous_function, args...)`
            if length(ex0.args) != 2
                return Expr(:call, :error, "ill-formed do call")
            end
            i = findlast(@nospecialize(a)->(isexpr(a, :kw) || isexpr(a, :parameters)), ex0.args[1].args)
            args = copy(ex0.args[1].args)
            insert!(args, (isnothing(i) ? 2 : 1+i::Int), ex0.args[2])
            ex0 = Expr(:call, args...)
        end
        if is_broadcasting_expr(ex0) && !is_source_reflection
            # Manually wrap top-level broadcasts in a function.
            # We don't do that if `fcn` reflects into the source,
            # because that destroys provenance information.
            args = Any[]
            ex, i = recursive_dotcalls!(copy(ex0), args)