@@ -261,27 +261,62 @@ partial def hasCDot : Syntax → Bool
261
261
- `f · · b` => `fun _a_1 _a_2 => f _a_1 _a_2 b` -/
262
262
partial def expandCDot? (stx : Term) : MacroM (Option Term) := do
263
263
if hasCDot stx then
264
- let (newStx, binders) ← (go stx).run #[]
264
+ let numArgs ← countArgs stx
265
+ let (newStx, binders) ← withFreshMacroScope <| (go numArgs stx).run #[]
265
266
`(fun $binders* => $(⟨newStx⟩))
266
267
else
267
268
pure none
268
269
where
269
270
/--
270
- Auxiliary function for expanding the `·` notation.
271
- The extra state `Array Syntax` contains the new binder names.
272
- If `stx` is a `·`, we create a fresh identifier, store in the
273
- extra state, and return it. Otherwise, we just return `stx`. -/
274
- go : Syntax → StateT (Array Ident) MacroM Syntax
275
- | stx@`(($(_))) => pure stx
276
- | stx@`(·) => withFreshMacroScope do
277
- let id ← mkFreshIdent stx (canonical := true )
278
- modify (·.push id)
279
- pure id
280
- | stx => match stx with
281
- | .node _ k args => do
282
- let args ← args.mapM go
283
- return .node (.fromRef stx (canonical := true )) k args
284
- | _ => pure stx
271
+ Count arguments, taking into consideration choice nodes
272
+ and validating that each alternative has the same number of arguments.
273
+ -/
274
+ countArgs : Syntax → MacroM Nat
275
+ | `(($_)) => return 0
276
+ | `(·) => return 1
277
+ | stx =>
278
+ match stx with
279
+ | .node _ k args => do
280
+ if k == choiceKind then
281
+ if args.isEmpty then
282
+ Macro.throwUnsupported
283
+ let counts ← args.mapM countArgs
284
+ unless counts.all (fun c => counts[0 ]! == c) do
285
+ Macro.throwErrorAt stx "Ambiguous notation in cdot function has different numbers of '·' arguments in each alternative."
286
+ return counts[0 ]!
287
+ else
288
+ args.foldlM (init := 0 ) (fun acc arg => return acc + (← countArgs arg))
289
+ | _ => return 0
290
+ /--
291
+ Auxiliary function for expanding the `·` notation.
292
+ The extra state `Array Syntax` contains the new binder names.
293
+ If `stx` is a `·`, we create a fresh identifier, store it in the
294
+ extra state, and return it. Otherwise, we just return `stx`.
295
+ -/
296
+ go (numArgs : Nat) : Syntax → StateT (Array Ident) MacroM Syntax
297
+ | stx@`(($(_))) => pure stx
298
+ | stx@`(·) => do
299
+ let i := (← get).size
300
+ let name ← MonadQuotation.addMacroScope <|
301
+ if numArgs == 1 then
302
+ `x
303
+ else
304
+ Name.mkSimple s! "x{ i + 1 } "
305
+ let id := mkIdentFrom stx name (canonical := true )
306
+ modify (fun s => s.push id)
307
+ pure id
308
+ | stx => match stx with
309
+ | .node _ k args => do
310
+ let args ←
311
+ if k == choiceKind then
312
+ let s ← get
313
+ let args' ← args.mapM (fun arg => go numArgs arg |>.run s)
314
+ set args'[0 ]!.2
315
+ pure <| args'.map Prod.fst
316
+ else
317
+ args.mapM (go numArgs)
318
+ return .node (.fromRef stx (canonical := true )) k args
319
+ | _ => pure stx
285
320
286
321
/--
287
322
Helper method for elaborating terms such as `(.+.)` where a constant name is expected.
0 commit comments