@@ -100,12 +100,13 @@ argconvert(@nospecialize(code_type), arg) = arg
100100extract_extra_options(@nospecialize(f), _) = (;)
101101separate_kwargs(code_type:: Val , args... ; kwargs... ) = (argconvert.(Ref(code_type), args), values(kwargs))
102102is_error_expr(expr) = Base. isexpr(expr, :call) && expr. args[1 ] in (:error, :throw)
103+ is_call_expr(expr) = Base. isexpr(expr, :call) || (Base. isexpr(expr, :(.), 2 ) && Base. isexpr(expr. args[2 ], :tuple))
103104
104105
105106function gen_code_for_diff_call(mod, expr, diff_options)
106107 # `diff_options` must be already `esc`aped, but not `expr`
107108
108- if ! Base . isexpr (expr, [:call, :(.)] )
109+ if ! is_call_expr (expr)
109110 error_str = " Expected call (or dot call) to function, got: $expr "
110111 return :(throw(ArgumentError($ error_str)))
111112 end
@@ -173,6 +174,23 @@ function gen_code_for_diff_call(mod, expr, diff_options)
173174end
174175
175176
177+ function code_diff_for_expr(code_expr, options, mod)
178+ if is_call_expr(code_expr)
179+ # Generic call comparison
180+ return gen_code_for_diff_call(mod, code_expr, options)
181+ else
182+ if Base. isexpr(code_expr, :quote)
183+ # AST comparison
184+ type_guess = (Expr(:kw, :type, QuoteNode(:ast)),)
185+ else
186+ # Mystery comparison
187+ type_guess = ()
188+ end
189+ return :($ code_for_diff($ (esc(code_expr)); $ (type_guess... ), $ (options... )))
190+ end
191+ end
192+
193+
176194"""
177195 @code_diff [type=:native] [color=true] [cleanup=true] [option=value...] f₁(...) f₂(...)
178196 @code_diff [option=value...] :(expr₁) :(expr₂)
@@ -256,17 +274,10 @@ macro code_diff(args...)
256274 code₁ isa QuoteNode && (code₁ = Expr(:quote, Expr(:block, code₁. value)))
257275 code₂ isa QuoteNode && (code₂ = Expr(:quote, Expr(:block, code₂. value)))
258276
259- if Base. isexpr(code₁, :quote) && Base. isexpr(code₂, :quote)
260- code₁ = esc(code₁)
261- code₂ = esc(code₂)
262- code_for_diff₁ = :($ code_for_diff($ code₁; type= :ast, $ (options₁... )))
263- code_for_diff₂ = :($ code_for_diff($ code₂; type= :ast, $ (options₂... )))
264- else
265- code_for_diff₁ = gen_code_for_diff_call(__module__, code₁, options₁)
266- code_for_diff₂ = gen_code_for_diff_call(__module__, code₂, options₂)
267- is_error_expr(code_for_diff₁) && return code_for_diff₁
268- is_error_expr(code_for_diff₂) && return code_for_diff₂
269- end
277+ code_for_diff₁ = code_diff_for_expr(code₁, options₁, __module__)
278+ code_for_diff₂ = code_diff_for_expr(code₂, options₂, __module__)
279+ is_error_expr(code_for_diff₁) && return code_for_diff₁
280+ is_error_expr(code_for_diff₂) && return code_for_diff₂
270281
271282 return quote
272283 let
@@ -342,15 +353,10 @@ macro code_for(args...)
342353 # Simple values such as `:(1)` are stored in a `QuoteNode`
343354 code isa QuoteNode && (code = Expr(:quote, Expr(:block, code. value)))
344355
356+ # Place the diff options in a temp variable in order to extract `io` at runtime
345357 diff_options = esc(gensym(:diff_options))
346-
347- if Base. isexpr(code, :quote)
348- code = esc(code)
349- code_for = :($ code_for_diff($ code; type= :ast, $ (options... )))
350- else
351- code_for = gen_code_for_diff_call(__module__, code, [:($ diff_options... )])
352- is_error_expr(code_for) && return code_for
353- end
358+ code_for = code_diff_for_expr(code, [:($ diff_options... )], __module__)
359+ is_error_expr(code_for) && return code_for
354360
355361 return quote
356362 let
0 commit comments