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

Code before:
function macroexpand(mod::Module, ex; expr_compat_mode=false, world=Base.get_world_counter())
    ctx1, ex1 = expand_forms_1(mod, ex, expr_compat_mode, world)
    ex1
end

# Incremental lowering API which can manage toplevel and module expressions.
#
# This iteration API is oddly bespoke and arguably somewhat non-Julian for two
# reasons:
#
# * Lowering knows when new modules are required, and may request them with
#   `:begin_module`. However `eval()` generates those modules so they need to
#   be passed back into lowering. So we can't just use `Base.iterate()`. (Put a
#   different way, we have a situation which is suited to coroutines but we
#   don't want to use full Julia `Task`s for this.)
# * We might want to implement this `eval()` in Julia's C runtime code or early
#   in bootstrap. Hence using SimpleVector and Symbol as the return values of
#   `lower_step()`
#
# We might consider changing at least the second of these choices, depending on
# how we end up putting this into Base.

struct LoweringIterator{GraphType}
    # We don't currently use this iterator outside of eval (which should always
    # use the latest world), but this is necessary for passing it in if we did
    init_world::UInt
    expr_compat_mode::Bool # later stored in module?
    todo::Vector{Tuple{SyntaxTree{GraphType}, Bool, Int}}
end

function lower_init(ex::SyntaxTree{T}, init_world::UInt;
                    expr_compat_mode::Bool=false) where {T}
    LoweringIterator{T}(init_world, expr_compat_mode, [(ex, false, 0)])
end

function lower_step(iter, mod, world=iter.init_world)
    if isempty(iter.todo)
        return Core.svec(:done)
    end

    top_ex, is_module_body, child_idx = pop!(iter.todo)
    if child_idx > 0
        if child_idx <= numchildren(top_ex)
            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, Base.get_world_counter())
        end
    else

Review comment (suggestion):
`macro_world` or `initial_macro_world` might be more consistent with the name / usage in `MacroExpansionContext`

Code after:
function macroexpand(mod::Module, ex; expr_compat_mode=false, world=Base.get_world_counter())
    ctx1, ex1 = expand_forms_1(mod, ex, expr_compat_mode, world)
    ex1
end

# Incremental lowering API which can manage toplevel and module expressions.
#
# This iteration API is oddly bespoke and arguably somewhat non-Julian for two
# reasons:
#
# * Lowering knows when new modules are required, and may request them with
#   `:begin_module`. However `eval()` generates those modules so they need to
#   be passed back into lowering. So we can't just use `Base.iterate()`. (Put a
#   different way, we have a situation which is suited to coroutines but we
#   don't want to use full Julia `Task`s for this.)
# * We might want to implement this `eval()` in Julia's C runtime code or early
#   in bootstrap. Hence using SimpleVector and Symbol as the return values of
#   `lower_step()`
#
# We might consider changing at least the second of these choices, depending on
# how we end up putting this into Base.

struct LoweringIterator{GraphType}
    expr_compat_mode::Bool # later stored in module?
    todo::Vector{Tuple{SyntaxTree{GraphType}, Bool, Int}}
end

function lower_init(ex::SyntaxTree{T};
                    expr_compat_mode::Bool=false) where {T}
    LoweringIterator{T}(expr_compat_mode, [(ex, false, 0)])
end

function lower_step(iter, mod, world=Base.get_world_counter())
    if isempty(iter.todo)
        return Core.svec(:done)
    end

    top_ex, is_module_body, child_idx = pop!(iter.todo)
    if child_idx > 0
        if child_idx <= numchildren(top_ex)
            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