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

Code before:
    # TODO: metas
    is_literal(k) || is_identifier_like(ex) || k == K"Symbol" ||
        k == K"inert" || k == K"inert_syntaxtree" || k == K"top" ||
        k == K"core" || k == K"Value"
    # flisp also includes `a.b` with simple `a`, but this seems like a bug
    # because this calls the user-defined getproperty?
end

function check_no_parameters(ex::SyntaxTree, msg)
    i = find_parameters_ind(children(ex))
    if i > 0
        throw(LoweringError(ex[i], msg))
    end
end

function check_no_assignment(exs, msg="misplaced assignment statement in `[ ... ]`")
    i = findfirst(kind(e) == K"=" || kind(e) == K"kw" for e in exs)
    if !isnothing(i)
        throw(LoweringError(exs[i], msg))
    end
end

# Generating a new_local_binding or ssaval should only be done if we can
# guarantee there's some scope it's declared in, and that it's not declared or
# used outside of that scope (binding capture is OK).  This is the alternative.
function fresh_sym(ctx, srcref::SyntaxTree, name::String)
    @ast ctx srcref name::K"Identifier"(scope_layer=new_scope_layer(ctx))
end

#-------------------------------------------------------------------------------
# Destructuring

# Convert things like `(x,y,z) = (a,b,c)` to assignments, eliminating the
# tuple. Includes support for slurping/splatting. This function assumes that
# `_tuple_sides_match` returns true, so the following have already been
# checked:
#   * There's max one `...` on the left hand side
#   * There's max one `...` on the right hand side, in the last place, or
#     matched with an lhs... in the last place. (required so that
#     pairwise-matching terms from the right is valid)
#   * Neither side has any key=val terms or parameter blocks
#
# Tuple elimination must act /as if/ the right hand side tuple was first
# constructed followed by destructuring. In particular, any side effects due to
# evaluating the individual terms in the right hand side tuple must happen in
# order.
function tuple_to_assignments(ctx, ex, is_const)
    lhs = ex[1]
    rhs = ex[2]
    wrap(asgn) = is_const ? (@ast ctx ex [K"const" asgn]) : asgn


Review comment (suggestion):
Looks reasonable. Hopefully it's not a problem to have a *lot* of scope layers... they are lighter than `BindingInfo` though so I guess it's fine!

It would be nice to ensure these never end up global "by mistake" in the same way that macro expanded identifiers skip accidentally becoming global by the use of the is_macro_expansion flag on the scope layer. I think we should rename that flag to implicit_toplevel_globals and use it here too.

How about calling it `newvar()` or `new_var()` I feel that would fit in a bit more neatly with the rest of the naming.

Code after:
    # TODO: metas
    is_literal(k) || is_identifier_like(ex) || k == K"Symbol" ||
        k == K"inert" || k == K"inert_syntaxtree" || k == K"top" ||
        k == K"core" || k == K"Value"
    # flisp also includes `a.b` with simple `a`, but this seems like a bug
    # because this calls the user-defined getproperty?
end

function check_no_parameters(ex::SyntaxTree, msg)
    i = find_parameters_ind(children(ex))
    if i > 0
        throw(LoweringError(ex[i], msg))
    end
end

function check_no_assignment(exs, msg="misplaced assignment statement in `[ ... ]`")
    i = findfirst(kind(e) == K"=" || kind(e) == K"kw" for e in exs)
    if !isnothing(i)
        throw(LoweringError(exs[i], msg))
    end
end

# Generating a new_local_binding or ssaval should only be done if we can
# guarantee there's some scope it's declared in, and that it's not declared or
# used outside of that scope (binding capture is OK).  This is the alternative.
function newsym(ctx, srcref::SyntaxTree, name::String)
    @ast ctx srcref name::K"Identifier"(scope_layer=new_scope_layer(ctx))
end

#-------------------------------------------------------------------------------
# Destructuring

# Convert things like `(x,y,z) = (a,b,c)` to assignments, eliminating the
# tuple. Includes support for slurping/splatting. This function assumes that
# `_tuple_sides_match` returns true, so the following have already been
# checked:
#   * There's max one `...` on the left hand side
#   * There's max one `...` on the right hand side, in the last place, or
#     matched with an lhs... in the last place. (required so that
#     pairwise-matching terms from the right is valid)
#   * Neither side has any key=val terms or parameter blocks
#
# Tuple elimination must act /as if/ the right hand side tuple was first
# constructed followed by destructuring. In particular, any side effects due to
# evaluating the individual terms in the right hand side tuple must happen in
# order.
function tuple_to_assignments(ctx, ex, is_const)
    lhs = ex[1]
    rhs = ex[2]
    wrap(asgn) = is_const ? (@ast ctx ex [K"const" asgn]) : asgn