diff --git a/src/ast.jl b/src/ast.jl index a7b087c..93f5a7c 100644 --- a/src/ast.jl +++ b/src/ast.jl @@ -70,6 +70,21 @@ Id for scope layers in macro expansion """ const LayerId = Int +""" +A `ScopeLayer` is a mechanism for automatic hygienic macros; every identifier +is assigned to a particular layer and can only match against bindings which are +themselves part of that layer. + +Normal code contains a single scope layer, whereas each macro expansion +generates a new layer. +""" +struct ScopeLayer + id::LayerId + mod::Module + parent_layer::LayerId # Index of parent layer in a macro expansion. Equal to 0 for no parent + is_macro_expansion::Bool # FIXME +end + #------------------------------------------------------------------------------- # AST creation utilities _node_id(graph::SyntaxGraph, ex::SyntaxTree) = (check_compatible_graph(graph, ex); ex._id) @@ -500,6 +515,10 @@ function adopt_scope(ex::SyntaxTree, scope_layer::LayerId) set_scope_layer(ex, ex, scope_layer, true) end +function adopt_scope(ex::SyntaxTree, layer::ScopeLayer) + adopt_scope(ex, layer.id) +end + function adopt_scope(ex::SyntaxTree, ref::SyntaxTree) adopt_scope(ex, ref.scope_layer) end diff --git a/src/macro_expansion.jl b/src/macro_expansion.jl index 84efb44..d48cb13 100644 --- a/src/macro_expansion.jl +++ b/src/macro_expansion.jl @@ -1,20 +1,5 @@ # Lowering pass 1: Macro expansion, simple normalizations and quote expansion -""" -A `ScopeLayer` is a mechanism for automatic hygienic macros; every identifier -is assigned to a particular layer and can only match against bindings which are -themselves part of that layer. - -Normal code contains a single scope layer, whereas each macro expansion -generates a new layer. -""" -struct ScopeLayer - id::LayerId - mod::Module - parent_layer::LayerId # Index of parent layer in a macro expansion. Equal to 0 for no parent - is_macro_expansion::Bool # FIXME -end - struct MacroExpansionContext{GraphType} <: AbstractLoweringContext graph::GraphType bindings::Bindings diff --git a/src/runtime.jl b/src/runtime.jl index e6b03ce..e7bd83c 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -343,9 +343,11 @@ function (g::GeneratedFunctionStub)(world::UInt, source::Method, @nospecialize a macro_world = typemax(UInt) ctx1 = MacroExpansionContext(graph, __module__, false, macro_world) + layer = only(ctx1.scope_layers) + # Run code generator - this acts like a macro expander and like a macro # expander it gets a MacroContext. - mctx = MacroContext(syntax_graph(ctx1), g.srcref, ctx1.scope_layers[end]) + mctx = MacroContext(syntax_graph(ctx1), g.srcref, layer) ex0 = g.gen(mctx, args...) if ex0 isa SyntaxTree if !is_compatible_graph(ctx1, ex0) @@ -370,10 +372,10 @@ function (g::GeneratedFunctionStub)(world::UInt, source::Method, @nospecialize a # Wrap expansion in a non-toplevel lambda and run scope resolution ex2 = @ast ctx2 ex0 [K"lambda"(is_toplevel_thunk=false, toplevel_pure=true) [K"block" - (string(n)::K"Identifier" for n in g.argnames)... + (adopt_scope(string(n)::K"Identifier", layer) for n in g.argnames)... ] [K"block" - (string(n)::K"Identifier" for n in g.spnames)... + (adopt_scope(string(n)::K"Identifier", layer) for n in g.spnames)... ] ex2 ] diff --git a/src/scope_analysis.jl b/src/scope_analysis.jl index 4d751a8..ce3f0fb 100644 --- a/src/scope_analysis.jl +++ b/src/scope_analysis.jl @@ -12,16 +12,9 @@ function Base.isless(a::NameKey, b::NameKey) (a.name, a.layer) < (b.name, b.layer) end -# Identifiers produced by lowering will have the following layer by default. -# -# To make new mutable variables without colliding names, lowering can -# - generate new var_id's directly (like the gensyms used by the old system) -# - create additional layers, though this may be unnecessary -const _lowering_internal_layer = -1 - function NameKey(ex::SyntaxTree) @chk kind(ex) == K"Identifier" - NameKey(ex.name_val, get(ex, :scope_layer, _lowering_internal_layer)) + NameKey(ex.name_val, ex.scope_layer) end #-------------------------------------------------------------------------------