@@ -21,57 +21,106 @@ struct InterpolationContext{Graph} <: AbstractLoweringContext
2121 current_index:: Ref{Int}
2222end
2323
24+ # Context for `Expr`-based AST interpolation in compat mode
25+ struct ExprInterpolationContext <: AbstractLoweringContext
26+ values:: Tuple
27+ current_index:: Ref{Int}
28+ end
29+
30+ # Helper functions to make shared interpolation code which works with both
31+ # SyntaxTree and Expr data structures.
32+ _interp_kind (ex:: SyntaxTree ) = kind (ex)
33+ function _interp_kind (@nospecialize (ex))
34+ return (ex isa Expr && ex. head === :quote ) ? K " quote" :
35+ (ex isa Expr && ex. head === :$ ) ? K " $" :
36+ K " None" # Other cases irrelevant to interpolation
37+ end
38+
39+ _children (ex:: SyntaxTree ) = children (ex)
40+ _children (@nospecialize (ex)) = ex isa Expr ? ex. args : ()
41+
42+ _numchildren (ex:: SyntaxTree ) = numchildren (ex)
43+ _numchildren (@nospecialize (ex)) = ex isa Expr ? length (ex. args) : 0
44+
45+ _syntax_list (ctx:: InterpolationContext ) = SyntaxList (ctx)
46+ _syntax_list (ctx:: ExprInterpolationContext ) = Any[]
47+
48+ _interp_makenode (ctx:: InterpolationContext , ex, args) = makenode (ctx, ex, ex, args)
49+ _interp_makenode (ctx:: ExprInterpolationContext , ex, args) = Expr ((ex:: Expr ). head, args... )
50+
51+ _to_syntax_tree (ex:: SyntaxTree ) = ex
52+ _to_syntax_tree (@nospecialize (ex)) = expr_to_syntaxtree (ex)
53+
54+
2455function _contains_active_interp (ex, depth)
25- k = kind (ex)
56+ k = _interp_kind (ex)
2657 if k == K " $" && depth == 0
2758 return true
59+ elseif _numchildren (ex) == 0
60+ return false
2861 end
2962 inner_depth = k == K " quote" ? depth + 1 :
3063 k == K " $" ? depth - 1 :
3164 depth
32- return any (_contains_active_interp (c, inner_depth) for c in children (ex))
65+ return any (_contains_active_interp (c, inner_depth) for c in _children (ex))
3366end
3467
3568# Produce interpolated node for `$x` syntax
36- function _interpolated_value (ctx, srcref, ex)
69+ function _interpolated_value (ctx:: InterpolationContext , srcref, ex)
3770 if ex isa SyntaxTree
3871 if ! is_compatible_graph (ctx, ex)
3972 ex = copy_ast (ctx, ex)
4073 end
4174 append_sourceref (ctx, ex, srcref)
75+ elseif ex isa Symbol
76+ # Plain symbols become identifiers. This is an accomodation for
77+ # compatibility to allow `:x` (a Symbol) and `:(x)` (a SyntaxTree) to
78+ # be used interchangably in macros.
79+ makeleaf (ctx, srcref, K " Identifier" , string (ex))
4280 else
4381 makeleaf (ctx, srcref, K " Value" , ex)
4482 end
4583end
4684
47- function _interpolate_ast (ctx:: InterpolationContext , ex, depth)
85+ function _interpolated_value (:: ExprInterpolationContext , _, ex)
86+ ex
87+ end
88+
89+ function copy_ast (:: ExprInterpolationContext , @nospecialize (ex))
90+ @ccall (jl_copy_ast (ex:: Any ):: Any )
91+ end
92+
93+ function _interpolate_ast (ctx, ex, depth)
4894 if ctx. current_index[] > length (ctx. values) || ! _contains_active_interp (ex, depth)
4995 return ex
5096 end
5197
5298 # We have an interpolation deeper in the tree somewhere - expand to an
53- # expression
54- inner_depth = kind (ex) == K " quote" ? depth + 1 :
55- kind (ex) == K " $" ? depth - 1 :
99+ # expression which performs the interpolation.
100+ k = _interp_kind (ex)
101+ inner_depth = k == K " quote" ? depth + 1 :
102+ k == K " $" ? depth - 1 :
56103 depth
57- expanded_children = SyntaxList (ctx)
58- for e in children (ex)
59- if kind (e) == K " $" && inner_depth == 0
104+
105+ expanded_children = _syntax_list (ctx)
106+
107+ for e in _children (ex)
108+ if _interp_kind (e) == K " $" && inner_depth == 0
60109 vals = ctx. values[ctx. current_index[]]:: Tuple
61110 ctx. current_index[] += 1
62111 for (i,v) in enumerate (vals)
63- srcref = numchildren (e) == 1 ? e : e [i]
112+ srcref = _numchildren (e) == 1 ? e : _children (e) [i]
64113 push! (expanded_children, _interpolated_value (ctx, srcref, v))
65114 end
66115 else
67116 push! (expanded_children, _interpolate_ast (ctx, e, inner_depth))
68117 end
69118 end
70119
71- makenode (ctx, ex, head (ex) , expanded_children)
120+ _interp_makenode (ctx, ex, expanded_children)
72121end
73122
74- function interpolate_ast (:: Type{SyntaxTree} , ex, values... )
123+ function _setup_interpolation (:: Type{SyntaxTree} , ex, values)
75124 # Construct graph for interpolation context. We inherit this from the macro
76125 # context where possible by detecting it using __macro_ctx__. This feels
77126 # hacky though.
@@ -92,30 +141,33 @@ function interpolate_ast(::Type{SyntaxTree}, ex, values...)
92141 value= Any, name_val= String, scope_layer= LayerId)
93142 end
94143 ctx = InterpolationContext (graph, values, Ref (1 ))
144+ return ctx
145+ end
146+
147+ function _setup_interpolation (:: Type{Expr} , ex, values)
148+ return ExprInterpolationContext (values, Ref (1 ))
149+ end
150+
151+ function interpolate_ast (:: Type{T} , ex, values... ) where {T}
152+ ctx = _setup_interpolation (T, ex, values)
153+
95154 # We must copy the AST into our context to use it as the source reference
96- # of generated expressions.
155+ # of generated expressions (and in the Expr case at least, to avoid mutation)
97156 ex1 = copy_ast (ctx, ex)
98- if kind (ex1) == K " $"
157+ if _interp_kind (ex1) == K " $"
99158 @assert length (values) == 1
100159 vs = values[1 ]
101160 if length (vs) > 1
102161 # :($($(xs...))) where xs is more than length 1
103- throw (LoweringError (ex1, " More than one value in bare `\$ ` expression" ))
162+ throw (LoweringError (_to_syntax_tree (ex1),
163+ " More than one value in bare `\$ ` expression" ))
104164 end
105165 _interpolated_value (ctx, ex1, only (vs))
106166 else
107167 _interpolate_ast (ctx, ex1, 0 )
108168 end
109169end
110170
111- function interpolate_ast (:: Type{Expr} , ex, values... )
112- # TODO : Adjust `_interpolated_value` to ensure that incoming `Expr` data
113- # structures are treated as AST in Expr compat mode, rather than `K"Value"`?
114- # Or convert `ex` to `Expr` early during lowering and implement
115- # `interpolate_ast` for `Expr`?
116- Expr (interpolate_ast (SyntaxTree, ex, values... ))
117- end
118-
119171# --------------------------------------------------
120172# Functions called by closure conversion
121173function eval_closure_type (mod:: Module , closure_type_name:: Symbol , field_names, field_is_box)
0 commit comments