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

Code before:
        gen = expand_forms_1(ctx, expand_quote(
            ctx, @ast ctx e2 [K"block" split_generated(e2, true)]))
        nongen = split_generated(e2, false)
        @ast ctx ex [K"generated_function" e1 gen nongen]
    elseif k == K"<:" || k == K">:" || k == K"-->"
        # TODO: Should every form get layerid systematically? Or only the ones
        # which expand_forms_2 needs?
        layerid = get(ex, :scope_layer, current_layer_id(ctx))
        setattr(mapchildren(e->expand_forms_1(ctx,e), ctx, ex),
                :scope_layer, layerid)
    else
        mapchildren(e->expand_forms_1(ctx,e), ctx, ex)
    end
end

has_if_generated(st::SyntaxTree) = JuliaSyntax.@stm st begin
    (_, when=is_leaf(st)||is_quoted(st)) -> false
    [K"function" _...] -> false
    ([K"=" call _], when=is_eventually_call(call)) -> false
    [K"if" [K"generated"] _ _] -> true
    _ -> any(has_if_generated, children(st))
end
split_generated(st::SyntaxTree, gen_part) = JuliaSyntax.@stm st begin
    (_, when=is_leaf(st)) -> st
    [K"if" [K"generated"] gen nongen] -> gen_part ?
        @ast(st._graph, st, [K"$" gen]) : nongen
    _ -> mapchildren(x->split_generated(x, gen_part), st._graph, st)
end

function ensure_macro_attributes(graph)
    ensure_attributes(graph,
                      var_id=IdTag,
                      scope_layer=LayerId,
                      __macro_ctx__=Nothing,
                      meta=CompileHints)
end

@fzone "JL: macroexpand" function expand_forms_1(mod::Module, ex::SyntaxTree, expr_compat_mode::Bool, macro_world::UInt)
    if kind(ex) == K"local"
        # This error assumes we're expanding the body of a top level thunk but
        # we might want to make that more explicit in the pass system.
        throw(LoweringError(ex, "local declarations have no effect outside a scope"))
    end
    graph = ensure_macro_attributes(syntax_graph(ex))
    ctx = MacroExpansionContext(graph, mod, expr_compat_mode, macro_world)
    ex2 = expand_forms_1(ctx, reparent(ctx, ex))
    graph2 = delete_attributes(graph, :__macro_ctx__)
    # TODO: Returning the context with pass-specific mutable data is a bad way
    # to carry state into the next pass. We might fix this by attaching such
    # data to the graph itself as global attributes?
    ctx2 = MacroExpansionContext(graph2, ctx.bindings, ctx.scope_layers, ctx.scope_layer_stack,

Review comment (suggestion):
nitpick, but this ternary is a bit hard to read
```suggestion
    [K"if" [K"generated"] gen nongen] -> if gen_part
        @ast st._graph st [K"$" gen]
    else
        nongen
    end
```

Code after:
        gen = expand_forms_1(ctx, expand_quote(
            ctx, @ast ctx e2 [K"block" split_generated(e2, true)]))
        nongen = split_generated(e2, false)
        @ast ctx ex [K"generated_function" e1 gen nongen]
    elseif k == K"<:" || k == K">:" || k == K"-->"
        # TODO: Should every form get layerid systematically? Or only the ones
        # which expand_forms_2 needs?
        layerid = get(ex, :scope_layer, current_layer_id(ctx))
        setattr(mapchildren(e->expand_forms_1(ctx,e), ctx, ex),
                :scope_layer, layerid)
    else
        mapchildren(e->expand_forms_1(ctx,e), ctx, ex)
    end
end

has_if_generated(st::SyntaxTree) = JuliaSyntax.@stm st begin
    (_, when=is_leaf(st)||is_quoted(st)) -> false
    [K"function" _...] -> false
    ([K"=" call _], when=is_eventually_call(call)) -> false
    [K"if" [K"generated"] _ _] -> true
    _ -> any(has_if_generated, children(st))
end
split_generated(st::SyntaxTree, gen_part) = JuliaSyntax.@stm st begin
    (_, when=is_leaf(st)||is_quoted(st)) -> st
    [K"if" [K"generated"] gen nongen] -> if gen_part
        @ast(st._graph, st, [K"$" gen])
    else
        nongen
    end
    _ -> mapchildren(x->split_generated(x, gen_part), st._graph, st)
end

function ensure_macro_attributes(graph)
    ensure_attributes(graph,
                      var_id=IdTag,
                      scope_layer=LayerId,
                      __macro_ctx__=Nothing,
                      meta=CompileHints)
end

@fzone "JL: macroexpand" function expand_forms_1(mod::Module, ex::SyntaxTree, expr_compat_mode::Bool, macro_world::UInt)
    if kind(ex) == K"local"
        # This error assumes we're expanding the body of a top level thunk but
        # we might want to make that more explicit in the pass system.
        throw(LoweringError(ex, "local declarations have no effect outside a scope"))
    end
    graph = ensure_macro_attributes(syntax_graph(ex))
    ctx = MacroExpansionContext(graph, mod, expr_compat_mode, macro_world)
    ex2 = expand_forms_1(ctx, reparent(ctx, ex))
    graph2 = delete_attributes(graph, :__macro_ctx__)
    # TODO: Returning the context with pass-specific mutable data is a bad way