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

Code before:
        return Core.svec(:done)
    end

    ex, is_module_body, child_idx = pop!(iter.todo)
    if child_idx > 0
        next_child = child_idx + 1
        if child_idx <= numchildren(ex)
            push!(iter.todo, (ex, is_module_body, next_child))
            ex = ex[child_idx]
        else
            if is_module_body
                pop_layer!(iter.ctx)
                return Core.svec(:end_module)
            else
                return lower_step(iter)
            end
        end
    end

    k = kind(ex)
    if !(k in KSet"toplevel module")
        ctx1 = let c = iter.ctx
            MacroExpansionContext(
                c.graph, c.bindings, c.scope_layers, c.scope_layer_stack,
                c.expr_compat_mode, world)
        end
        ex = expand_forms_1(ctx1, ex)
        k = kind(ex)
    end
    if k == K"toplevel"
        push!(iter.todo, (ex, false, 1))
        return lower_step(iter)
    elseif k == K"module"
        name = ex[1]
        if kind(name) != K"Identifier"
            throw(LoweringError(name, "Expected module name"))
        end
        newmod_name = Symbol(name.name_val)
        body = ex[2]
        if kind(body) != K"block"
            throw(LoweringError(body, "Expected block in module body"))
        end
        std_defs = !has_flags(ex, JuliaSyntax.BARE_MODULE_FLAG)
        loc = source_location(LineNumberNode, ex)
        push!(iter.todo, (body, true, 1))
        return Core.svec(:begin_module, newmod_name, std_defs, loc)
    else
        # Non macro expansion parts of lowering
        ctx2, ex2 = expand_forms_2(ctx1, ex)
        ctx3, ex3 = resolve_scopes(ctx2, ex2)
        ctx4, ex4 = convert_closures(ctx3, ex3)

Review comment (refactor):
This might be worth a separate helper / constructor

One common pattern is:
```julia
MacroExpansionContext(ctx::MacroExpansionContext; graph = ctx.graph, bindings = ctx.bindings, scope_layers = ctx.scope_layers, scope_layer_stack = ctx.scope_layer_stack, expr_compat_mode = ctx.expr_compat_mode, world = ctx.world) = MacroExpansionContext(graph, bindings, scope_layers, scope_layer_stack, expr_compat_mode, world)

ctx1 = MacroExpansionContext(iter.ctx; world = world)
```


Code after:
            push!(iter.todo, (top_ex, is_module_body, child_idx + 1))
            ex = top_ex[child_idx]
        elseif is_module_body
            return Core.svec(:end_module)
        else
            return lower_step(iter, mod)
        end
    else
        ex = top_ex
    end

    k = kind(ex)
    if !(k in KSet"toplevel module")
        ctx1, ex = expand_forms_1(mod, ex, iter.expr_compat_mode, world)
        k = kind(ex)
    end
    if k == K"toplevel"
        push!(iter.todo, (ex, false, 1))
        return lower_step(iter, mod)
    elseif k == K"module"
        name = ex[1]
        if kind(name) != K"Identifier"
            throw(LoweringError(name, "Expected module name"))
        end
        newmod_name = Symbol(name.name_val)
        body = ex[2]
        if kind(body) != K"block"
            throw(LoweringError(body, "Expected block in module body"))
        end
        std_defs = !has_flags(ex, JuliaSyntax.BARE_MODULE_FLAG)
        loc = source_location(LineNumberNode, ex)
        push!(iter.todo, (body, true, 1))
        return Core.svec(:begin_module, newmod_name, std_defs, loc)
    else
        # Non macro expansion parts of lowering
        ctx2, ex2 = expand_forms_2(ctx1, ex)
        ctx3, ex3 = resolve_scopes(ctx2, ex2)
        ctx4, ex4 = convert_closures(ctx3, ex3)
        ctx5, ex5 = linearize_ir(ctx4, ex4)
        thunk = to_lowered_expr(ex5)
        return Core.svec(:thunk, thunk)
    end
end


#-------------------------------------------------------------------------------

function codeinfo_has_image_globalref(@nospecialize(e))
    if e isa GlobalRef
        return 0x00 !== @ccall jl_object_in_image(e.mod::Any)::UInt8
    elseif e isa Core.CodeInfo