@@ -3,8 +3,6 @@ module FileCheck
33import LLVM_jll
44
55export @filecheck
6- export @check , @check_label , @check_next , @check_same ,
7- @check_not , @check_dag , @check_empty , @check_count
86
97global filecheck_path:: String
108function __init__ ()
@@ -139,71 +137,67 @@ function parse_kwargs(args)
139137 return kwargs
140138end
141139
142- # collect checks used in the @filecheck block by piggybacking on macro expansion
143- const checks = Tuple{Any,Bool,String,Any}[]
144-
145- macro check (args... )
146- kwargs = parse_kwargs (args[1 : end - 1 ])
147- cond = get (kwargs, :cond , nothing )
148- literal = get (kwargs, :literal , false )
149- push! (checks, (cond, literal, " CHECK" , args[end ]))
150- nothing
151- end
152-
153- macro check_label (args... )
154- kwargs = parse_kwargs (args[1 : end - 1 ])
155- cond = get (kwargs, :cond , nothing )
156- literal = get (kwargs, :literal , false )
157- push! (checks, (cond, literal, " CHECK-LABEL" , args[end ]))
158- nothing
159- end
160-
161- macro check_next (args... )
162- kwargs = parse_kwargs (args[1 : end - 1 ])
163- cond = get (kwargs, :cond , nothing )
164- literal = get (kwargs, :literal , false )
165- push! (checks, (cond, literal, " CHECK-NEXT" , args[end ]))
166- nothing
140+ # Generate @check* macros that can only be used inside @filecheck blocks
141+ const CHECK_MACROS = Dict {Symbol,String} (
142+ Symbol (" @check" ) => " CHECK" ,
143+ Symbol (" @check_label" ) => " CHECK-LABEL" ,
144+ Symbol (" @check_next" ) => " CHECK-NEXT" ,
145+ Symbol (" @check_same" ) => " CHECK-SAME" ,
146+ Symbol (" @check_not" ) => " CHECK-NOT" ,
147+ Symbol (" @check_dag" ) => " CHECK-DAG" ,
148+ Symbol (" @check_empty" ) => " CHECK-EMPTY" ,
149+ Symbol (" @check_count" ) => " CHECK-COUNT" ,
150+ )
151+ for (macro_sym, _) in CHECK_MACROS
152+ name = Symbol (string (macro_sym)[2 : end ]) # strip leading @
153+ @eval begin
154+ export $ (Symbol (" @" , name))
155+ macro $name (args... )
156+ error ($ (string (" @" , name, " can only be used inside a @filecheck block" )))
157+ end
158+ end
167159end
168160
169- macro check_same (args... )
170- kwargs = parse_kwargs (args[1 : end - 1 ])
171- cond = get (kwargs, :cond , nothing )
172- literal = get (kwargs, :literal , false )
173- push! (checks, (cond, literal, " CHECK-SAME" , args[end ]))
174- nothing
175- end
161+ # Walk the AST recursively, collecting @check* macrocall nodes and removing them from blocks.
162+ function extract_checks! (ex, collected:: Vector{Tuple{Any,Bool,String,Any}} )
163+ ex isa Expr || return ex
176164
177- macro check_not (args... )
178- kwargs = parse_kwargs (args[1 : end - 1 ])
179- cond = get (kwargs, :cond , nothing )
180- literal = get (kwargs, :literal , false )
181- push! (checks, (cond, literal, " CHECK-NOT" , args[end ]))
182- nothing
183- end
184-
185- macro check_dag (args... )
186- kwargs = parse_kwargs (args[1 : end - 1 ])
187- cond = get (kwargs, :cond , nothing )
188- literal = get (kwargs, :literal , false )
189- push! (checks, (cond, literal, " CHECK-DAG" , args[end ]))
190- nothing
191- end
165+ # Recurse into sub-expressions first (depth-first to collect in source order)
166+ for i in eachindex (ex. args)
167+ ex. args[i] = extract_checks! (ex. args[i], collected)
168+ end
192169
193- macro check_empty (args... )
194- kwargs = parse_kwargs (args[1 : end - 1 ])
195- cond = get (kwargs, :cond , nothing )
196- literal = get (kwargs, :literal , false )
197- push! (checks, (cond, literal, " CHECK-EMPTY" , args[end ]))
198- nothing
170+ # Strip @check* calls from blocks
171+ if Meta. isexpr (ex, :block )
172+ filter! (ex. args) do arg
173+ if Meta. isexpr (arg, :macrocall ) && haskey (CHECK_MACROS, arg. args[1 ])
174+ collect_check! (arg, collected)
175+ return false
176+ end
177+ true
178+ end
179+ end
180+ return ex
199181end
200182
201- macro check_count (args... )
202- kwargs = parse_kwargs (args[1 : end - 2 ])
203- cond = get (kwargs, :cond , nothing )
204- literal = get (kwargs, :literal , false )
205- push! (checks, (cond, literal, " CHECK-COUNT-$(args[end - 1 ]) " , args[end ]))
206- nothing
183+ # Extract a single check directive from a raw :macrocall AST node.
184+ # Raw AST args: [macro_sym, LineNumberNode, real_args...]
185+ function collect_check! (ex, collected)
186+ macro_sym = ex. args[1 ]:: Symbol
187+ check_type = CHECK_MACROS[macro_sym]
188+ # Skip macro name and LineNumberNodes
189+ real_args = [a for a in ex. args[2 : end ] if ! (a isa LineNumberNode)]
190+ if macro_sym === Symbol (" @check_count" )
191+ kwargs = parse_kwargs (real_args[1 : end - 2 ])
192+ cond = get (kwargs, :cond , nothing )
193+ literal = get (kwargs, :literal , false )
194+ push! (collected, (cond, literal, " CHECK-COUNT-$(real_args[end - 1 ]) " , real_args[end ]))
195+ else
196+ kwargs = parse_kwargs (real_args[1 : end - 1 ])
197+ cond = get (kwargs, :cond , nothing )
198+ literal = get (kwargs, :literal , false )
199+ push! (collected, (cond, literal, check_type, real_args[end ]))
200+ end
207201end
208202
209203"""
@@ -284,12 +278,12 @@ macro filecheck(args...)
284278 ex = args[end ]
285279 macro_kwargs = args[1 : end - 1 ]
286280
287- ex = Base. macroexpand (__module__, ex)
288- if isempty (checks)
281+ collected = Tuple{Any,Bool,String,Any}[]
282+ ex = extract_checks! (ex, collected)
283+ if isempty (collected)
289284 error (" No checks provided within the @filecheck macro block" )
290285 end
291- collected = copy (checks)
292- empty! (checks)
286+ ex = Base. macroexpand (__module__, ex)
293287
294288 # Build runtime code to conditionally collect check lines
295289 stmts = Expr[:(local _checks = String[])]
0 commit comments