Repository: JuliaLang/julia
File: JuliaLowering/src/compat.jl (Julia)

Code before:
        return Expr(:filter, _to_iterspec(exs[1].args[2:end], true), exs[1].args[1])
    end
    outex = Expr(:iteration)
    for e in exs
        if e.head === :block && !is_generator
            for iter in e.args
                push!(outex.args, Expr(:in, iter.args...))
            end
        elseif e.head === :(=)
            push!(outex.args, Expr(:in, e.args...))
        else
            @assert false "unknown iterspec in $e"
        end
    end
    return outex
end

"""
Return `e.args`, but with any parameters in SyntaxTree (flattened, source) order.
Parameters are expected to be at `e.args[pos]`.

e.g. orderings of (a,b,c;d;e;f):
  Expr:       (tuple (parameters (parameters (parameters f) e) d) a b c)
  SyntaxTree: (tuple a b c (parameters d) (parameters e) (parameters f))

`ensure_kw` converts `=` to `kw` within parameters blocks (needed for ref,
curly, vect, and braces).
"""
function collect_expr_parameters(e::Expr, pos::Int, ensure_kw::Bool)
    params = expr_parameters(e, pos)
    isnothing(params) && return copy(e.args)
    args = Any[e.args[1:pos-1]..., e.args[pos+1:end]...]
    return _flatten_params!(args, params, ensure_kw)
end
function _flatten_params!(out::Vector{Any}, params::Expr, ensure_kw)
    p,p_esc = unwrap_esc(params)
    p1 = expr_parameters(p, 1)
    if !isnothing(p1)
        p_args = ensure_kw ? map(_eq_to_kw, p.args[2:end]) : p.args[2:end]
        push!(out, p_esc(Expr(:parameters, p_args...)))
        _flatten_params!(out, p_esc(p1), ensure_kw)
    elseif ensure_kw && params isa Expr && params.head === :parameters
        push!(out, Expr(:parameters, map(_eq_to_kw, params.args)...))
    else
        push!(out, params::Any)
    end
    return out
end
function expr_parameters(p::Expr, pos::Int)
    if pos <= length(p.args)
        e,_ = unwrap_esc(p.args[pos])

Review comment (suggestion):
Conceptually this is:
```julia
map!(collect_expr_parameters(e, pos)) do arg
    Meta.isexpr(arg, :parameters) ? _eq_to_kw(arg) : arg
end
```
is that right?

If so, may be clearer just to transform after the fact, since 1 / 3 usages already needs a fix-up anyway

Code after:
            end
        elseif e.head === :(=)
            push!(outex.args, Expr(:in, e.args...))
        else
            @assert false "unknown iterspec in $e"
        end
    end
    return outex
end

"""
Return `e.args`, but with any parameters in SyntaxTree (flattened, source) order.
Parameters are expected to be at `e.args[pos]`.

e.g. orderings of (a,b,c;d;e;f):
  Expr:       (tuple (parameters (parameters (parameters f) e) d) a b c)
  SyntaxTree: (tuple a b c (parameters d) (parameters e) (parameters f))
"""
function collect_expr_parameters(e::Expr, pos::Int)
    params = expr_parameters(e, pos)
    isnothing(params) && return copy(e.args)
    args = Any[e.args[1:pos-1]..., e.args[pos+1:end]...]
    return _flatten_params!(args, params)
end
function _flatten_params!(out::Vector{Any}, params::Expr)
    p,p_esc = unwrap_esc(params)
    p1 = expr_parameters(p, 1)
    if !isnothing(p1)
        push!(out, p_esc(Expr(:parameters, p.args[2:end]...)))
        _flatten_params!(out, p_esc(p1))
    else
        push!(out, params::Any)
    end
    return out
end
function expr_parameters(p::Expr, pos::Int)
    if pos <= length(p.args)
        e,_ = unwrap_esc(p.args[pos])
        if e isa Expr && e.head === :parameters
            return p.args[pos]
        end
    end
    return nothing
end

"""
If `b` (usually a block) has exactly one non-LineNumberNode argument, unwrap it.
"""
function maybe_unwrap_arg(b)
    if !(b isa Expr)
        return b